• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

MixinFactory/H28-Nov-2004-680272

t/H28-Nov-2004-326219

CHANGESH A D28-Nov-2004486 2414

MANIFESTH A D16-Nov-2004435 2221

MANIFEST.SKIPH A D16-Nov-2004193 1616

META.ymlH A D28-Nov-2004310 119

Makefile.PLH A D28-Nov-20041.1 KiB4728

MixinFactory.pmH A D28-Nov-20045.7 KiB18828

READMEH A D28-Nov-200410.5 KiB265200

README

1NAME
2    Class::MixinFactory::ReadMe - About the Mixin Class Factory
3
4SYNOPSIS
5      package MyClass;
6      use Class::MixinFactory -hasafactory;
7      sub new { ... }
8      sub foo { return "Foo Bar" }
9
10      package MyClass::Logging;
11      sub foo { warn "Calling foo"; (shift)->NEXT('foo', @_) }
12
13      package MyClass::UpperCase;
14      sub foo { uc( (shift)->NEXT('foo', @_) ) }
15
16      package main;
17
18      my $class = MyClass->class( 'Logging', 'UpperCase' );
19
20      print $class->new()->foo();
21      # Calls MyClass::Logging::foo, MyClass::UpperCase::foo, MyClass::foo
22
23ABSTRACT
24    This distribution facilitates the run-time generation of classes which
25    inherit from a base class and some optional selection of mixin classes.
26
27    A factory is provided to generate the mixed classes with multiple
28    inheritance. A NEXT method allows method redispatch up the inheritance
29    chain.
30
31MOTIVATION
32  The Challenge
33
34    When developing an object class that will be used by different people
35    for different purposes, I find myself drawn to solutions in which a
36    minimal base class provides the shared behavior they all need, and a
37    collection of subclasses provides layers of additional functionality.
38
39    For example, consider a text templating framework, which might be
40    separated into several elements:
41
42    *   a base class, which provides methods to convert marked-up text into
43        runnable code,
44
45    *   an extension which enhances security by runing the code in a Safe
46        compartment,
47
48    *   an extension which feeds output through an HTML-escaping filter, and
49
50    *   an extension which records internal profiling data for benchmarking
51        purposes.
52
53    (See Text::MicroMason for an example of this design.)
54
55  A Bad Approach
56
57    A naive implementation of this might use a subclass for each behaviour,
58    and look like the following:
59
60                        +---------+
61                        |   Base  |
62                        +---------+
63                             |
64           +-----------------+-----------------+
65           v                 v                 v
66      +---------+       +---------+       +---------+
67      |Benchmark|       |  Filter |       |   Safe  | @ISA=qw(Base)
68      +---------+       +---------+       +---------+
69
70    The well-known problem with this implementation appears when you want to
71    combine several features:
72
73                        +---------+
74                        |   Base  |
75                        +---------+
76                             |
77           +-----------------+-----------------+
78           v                 v                 v
79      +---------+       +---------+       +---------+
80      |Benchmark|       |  Filter |       |   Safe  | @ISA=qw(Base)
81      +---------+       +---------+       +---------+
82                             |                 |
83                             +--------+--------+
84                                      v
85                               +-------------+
86                               | Safe_Filter | @ISA=qw(Filter Safe)
87                               +-------------+
88
89    This is the dreaded "diamond inheritance" problem: if Base provides a
90    compile() method, which Filter and Safe each override to perform
91    additional actions before or after calling SUPER::compile(), how can we
92    ensure they are all called in the correct sequence?
93
94  A Good Approach
95
96    The standard software engineering solution is to replace the use of
97    inheritance with decomposition into several different classes of
98    objects, which then cooperate through decoration and delegation; for
99    example, using separate classes for a resolver, a lexer, a parser, a
100    compiler, and an output channel. (See HTML::Mason for an example of this
101    design.)
102
103    Indeed, composition is an underutilized design technique, and there are
104    many times when inheritance is not the best tool to use. But of course,
105    in Perl there's more than one way to solve this problem, one of which is
106    facilitated by this distribution.
107
108  A Different Approach
109
110    We can rearrange our class hierarchy to avoid diamond inheritance by
111    using a base and a collection of mixin classes, which don't directly
112    inherit from the base class:
113
114      +---------+       +---------+       +---------+       +---------+
115      |Benchmark|       |  Filter |       |   Safe  |       |   Base  |
116      +---------+       +---------+       +---------+       +---------+
117                             |                 |                 |
118                             +-----------------+-----------------+
119                                               v
120                                        +-------------+
121                                        | Safe_Filter | @ISA=qw(Filter
122                                        +-------------+     Safe Base)
123
124    However, in this condition our mixin classes can't call SUPER methods at
125    all! Instead, another redispatch mechanism is needed, one that is able
126    to back-track through the inheritance tree and explore other branches.
127    (See the NEXT manpage for such an implementation.)
128
129    The order in which mixins are stacked is significant, so the caller does
130    need to have some understanding of how their behaviors interact. For
131    example, you'd typically want to ensure that the Benchmarking mixin was
132    the first in the chain, so that it could time everything later in the
133    sequence.
134
135  This Distribution
136
137    The Class::MixinFactory distribution provides serveral elements to
138    facilitate tihs kind of dynamic mixin architecture. The top level
139    package is just a facade that loads the other necessary classes and
140    provides a few import options for compile-time convenience. (See the
141    Class::MixinFactory manpage.)
142
143    To generate an object with some combination of mixins, you first use a
144    mixin factory to generate a mixed class. If a class with that
145    combination of classes has already been created, it is reused. You can
146    add a factory method to your base class, create a separate factory
147    object, or inherit to produce a factory class. (See the
148    Class::MixinFactory::Factory manpage.)
149
150    To allow mixin classes to redispatch to subsequent classes, all mixed
151    classes also inherit from a class which provides a NEXT() method. (If
152    you would prefer, your mixin class can alternately use the AUTOLOAD
153    solution provided by the NEXT::ACTUAL module from CPAN, or any other
154    equivalent re-dispatch mechanism.) (See the Class::MixinFactory::NEXT
155    manpage.)
156
157RELATED MODULES
158    There are number of other modules on CPAN that also support mixins,
159    method importing, or run-time multiple inheritance, while others don't
160    use mixins but are addressing a similar area of concern.
161
162    *   The mixin, Class::Mixin, and Spiffy modules support mixin classes
163        but don't have a configurable factory object or support run-time
164        mixin selection.
165
166    *   The Class::Mix and Class::Mutator modules provide run-time class
167        generation with multiple inheritance, but don't provide a
168        configurable factory object or a redispatch technique.
169
170    *   The Class::Factory module has a factory interface, but doesn't
171        support multiple inheritance.
172
173    *   The NEXT module provides a backtracking equivalent to SUPER similar
174        to the NEXT method included here, but uses AUTOLOAD rather than a
175        universal method.
176
177    *   The Class::Delegate and other modules support decoration to address
178        this problem via decomposition.
179
180    *   The Class::Role, Class::Roles and Class::Trait modules support
181        composing shared behaviors into your class.
182
183VERSION
184    This is version 0.92.
185
186    Elements of the interface remain open to change.
187
188BUGS
189    This module is new and relatively untested.
190
191    Please report any problems you encounter to the author at the below
192    address.
193
194INSTALLATION
195    This module should work with any version of Perl 5, without platform
196    dependencies or additional modules beyond the core distribution.
197
198    You should be able to install this module using the CPAN shell
199    interface:
200
201      perl -MCPAN -e 'install Class::MixinFactory'
202
203    Alternately, you may retrieve this package from CPAN
204    ("http://search.cpan.org/~evo/") or from the author's site
205    ("http://www.evoscript.org/Class-MixinFactory").
206
207    After downloading the distribution, follow the normal procedure to
208    unpack and install it, using the commands shown below or their local
209    equivalents on your system:
210
211      tar xzf Class-MixinFactory-*.tar.gz
212      cd Class-MixinFactory-*
213      perl Makefile.PL
214      make test && sudo make install
215
216SUPPORT
217    If you have questions or feedback about this module, please feel free to
218    contact the author at the below address. Although there is no formal
219    support program, I do attempt to answer email promptly.
220
221    I would be particularly interested in any suggestions towards improving
222    the documentation, correcting any Perl-version or platform dependencies,
223    as well as general feedback and suggested additions.
224
225    Bug reports that contain a failing test case are greatly appreciated,
226    and suggested patches will be promptly considered for inclusion in
227    future releases.
228
229    To report bugs via the CPAN web tracking system, go to
230    "http://rt.cpan.org/NoAuth/Bugs.html?Dist=Class-MixinFactory" or send
231    mail to "Dist=Class-MixinFactory#rt.cpan.org", replacing "#" with "@".
232
233    If you've found this module useful or have feedback about your
234    experience with it, consider sharing your opinion with other Perl users
235    by posting your comment to CPAN's ratings system
236    ("http://cpanratings.perl.org/rate/?distribution=Class-MixinFactory").
237
238    For more general discussion, you may wish to post a message on PerlMonks
239    ("http://perlmonks.org/?node=Seekers%20of%20Perl%20Wisdom") or on the
240    comp.lang.perl.misc newsgroup
241    ("http://groups.google.com/groups?group=comp.lang.perl.misc").
242
243AUTHOR
244    Developed by Matthew Simon Cavalletto at Evolution Softworks. You may
245    contact the author directly at "evo#cpan.org" or
246    "simonm#cavalletto.org", replacing "#" with "@".
247
248    Custom development and technical consulting are available at
249    "www.evolutionsoftworks.com". More free Perl software is available at
250    "www.evoscript.org".
251
252THANKS
253    My sincere thanks to the Perl Monks community for their feedback on
254    earlier versions of this commentary.
255
256      http://perlmonks.org/index.pl?node_id=398061
257      http://perlmonks.org/index.pl?node_id=399040
258
259LICENSE
260    Copyright 2004 Matthew Simon Cavalletto.
261
262    You may use, modify, and distribute this software under the same terms
263    as Perl.
264
265