1Class::Container(3) User Contributed Perl Documentation Class::Container(3)
2
3
4
6 Class::Container - Glues object frameworks together transparently
7
9 package Car;
10 use Class::Container;
11 @ISA = qw(Class::Container);
12
13 __PACKAGE__->valid_params
14 (
15 paint => {default => 'burgundy'},
16 style => {default => 'coupe'},
17 windshield => {isa => 'Glass'},
18 radio => {isa => 'Audio::Device'},
19 );
20
21 __PACKAGE__->contained_objects
22 (
23 windshield => 'Glass::Shatterproof',
24 wheel => { class => 'Vehicle::Wheel',
25 delayed => 1 },
26 radio => 'Audio::MP3',
27 );
28
29 sub new {
30 my $package = shift;
31
32 # 'windshield' and 'radio' objects are created automatically by
33 # SUPER::new()
34 my $self = $package->SUPER::new(@_);
35
36 $self->{right_wheel} = $self->create_delayed_object('wheel');
37 ... do any more initialization here ...
38 return $self;
39 }
40
42 This class facilitates building frameworks of several classes that
43 inter-operate. It was first designed and built for "HTML::Mason", in
44 which the Compiler, Lexer, Interpreter, Resolver, Component, Buffer,
45 and several other objects must create each other transparently, passing
46 the appropriate parameters to the right class, possibly substituting
47 other subclasses for any of these objects.
48
49 The main features of "Class::Container" are:
50
51 · Explicit declaration of containment relationships (aggregation,
52 factory creation, etc.)
53
54 · Declaration of constructor parameters accepted by each member in a
55 class framework
56
57 · Transparent passing of constructor parameters to the class that
58 needs them
59
60 · Ability to create one (automatic) or many (manual) contained
61 objects automatically and transparently
62
63 Scenario
64
65 Suppose you've got a class called "Parent", which contains an object of
66 the class "Child", which in turn contains an object of the class
67 "GrandChild". Each class creates the object that it contains. Each
68 class also accepts a set of named parameters in its "new()" method.
69 Without using "Class::Container", "Parent" will have to know all the
70 parameters that "Child" takes, and "Child" will have to know all the
71 parameters that "GrandChild" takes. And some of the parameters
72 accepted by "Parent" will really control aspects of "Child" or "Grand‐
73 Child". Likewise, some of the parameters accepted by "Child" will
74 really control aspects of "GrandChild". So, what happens when you
75 decide you want to use a "GrandDaughter" class instead of the generic
76 "GrandChild"? "Parent" and "Child" must be modified accordingly, so
77 that any additional parameters taken by "GrandDaughter" can be accommo‐
78 dated. This is a pain - the kind of pain that object-oriented program‐
79 ming was supposed to shield us from.
80
81 Now, how can "Class::Container" help? Using "Class::Container", each
82 class ("Parent", "Child", and "GrandChild") will declare what arguments
83 they take, and declare their relationships to the other classes ("Par‐
84 ent" creates/contains a "Child", and "Child" creates/contains a "Grand‐
85 Child"). Then, when you create a "Parent" object, you can pass "Par‐
86 ent->new()" all the parameters for all three classes, and they will
87 trickle down to the right places. Furthermore, "Parent" and "Child"
88 won't have to know anything about the parameters of its contained
89 objects. And finally, if you replace "GrandChild" with "GrandDaugh‐
90 ter", no changes to "Parent" or "Child" will likely be necessary.
91
93 new()
94
95 Any class that inherits from "Class::Container" should also inherit its
96 "new()" method. You can do this simply by omitting it in your class,
97 or by calling "SUPER::new(@_)" as indicated in the SYNOPSIS. The
98 "new()" method ensures that the proper parameters and objects are
99 passed to the proper constructor methods.
100
101 At the moment, the only possible constructor method is "new()". If you
102 need to create other constructor methods, they should call "new()"
103 internally.
104
105 __PACKAGE__->contained_objects()
106
107 This class method is used to register what other objects, if any, a
108 given class creates. It is called with a hash whose keys are the
109 parameter names that the contained class's constructor accepts, and
110 whose values are the default class to create an object of.
111
112 For example, consider the "HTML::Mason::Compiler" class, which uses the
113 following code:
114
115 __PACKAGE__->contained_objects( lexer => 'HTML::Mason::Lexer' );
116
117 This defines the relationship between the "HTML::Mason::Compiler" class
118 and the class it creates to go in its "lexer" slot. The
119 "HTML::Mason::Compiler" class "has a" "lexer". The "HTML::Mason::Com‐
120 piler->new()" method will accept a "lexer" parameter and, if no such
121 parameter is given, an object of the "HTML::Mason::Lexer" class should
122 be constructed.
123
124 We implement a bit of magic here, so that if "HTML::Mason::Com‐
125 piler->new()" is called with a "lexer_class" parameter, it will load
126 the indicated class (presumably a subclass of "HTML::Mason::Lexer"),
127 instantiate a new object of that class, and use it for the Compiler's
128 "lexer" object. We're also smart enough to notice if parameters given
129 to "HTML::Mason::Compiler->new()" actually should go to the "lexer"
130 contained object, and it will make sure that they get passed along.
131
132 Furthermore, an object may be declared as "delayed", which means that
133 an object won't be created when its containing class is constructed.
134 Instead, these objects will be created "on demand", potentially more
135 than once. The constructors will still enjoy the automatic passing of
136 parameters to the correct class. See the "create_delayed_object()" for
137 more.
138
139 To declare an object as "delayed", call this method like this:
140
141 __PACKAGE__->contained_objects( train => { class => 'Big::Train',
142 delayed => 1 } );
143
144 __PACKAGE__->valid_params(...)
145
146 Specifies the parameters accepted by this class's "new()" method as a
147 set of key/value pairs. Any parameters accepted by a superclass/sub‐
148 class will also be accepted, as well as any parameters accepted by con‐
149 tained objects. This method is a get/set accessor method, so it
150 returns a reference to a hash of these key/value pairs. As a special
151 case, if you wish to set the valid params to an empty set and you pre‐
152 viously set it to a non-empty set, you may call "__PACK‐
153 AGE__->valid_params(undef)".
154
155 "valid_params()" is called with a hash that contains parameter names as
156 its keys and validation specifications as values. This validation
157 specification is largely the same as that used by the "Params::Vali‐
158 date" module, because we use "Params::Validate" internally.
159
160 As an example, consider the following situation:
161
162 use Class::Container;
163 use Params::Validate qw(:types);
164 __PACKAGE__->valid_params
165 (
166 allow_globals => { type => ARRAYREF, parse => 'list', default => [] },
167 default_escape_flags => { type => SCALAR, parse => 'string', default => '' },
168 lexer => { isa => 'HTML::Mason::Lexer' },
169 preprocess => { type => CODEREF, parse => 'code', optional => 1 },
170 postprocess_perl => { type => CODEREF, parse => 'code', optional => 1 },
171 postprocess_text => { type => CODEREF, parse => 'code', optional => 1 },
172 );
173
174 __PACKAGE__->contained_objects( lexer => 'HTML::Mason::Lexer' );
175
176 The "type", "default", and "optional" parameters are part of the vali‐
177 dation specification used by "Params::Validate". The various constants
178 used, "ARRAYREF", "SCALAR", etc. are all exported by "Params::Vali‐
179 date". This means that any of these six parameter names, plus the
180 "lexer_class" parameter (because of the "contained_objects()" specifi‐
181 cation given earlier), are valid arguments to the Compiler's "new()"
182 method.
183
184 Note that there are also some "parse" attributes declared. These have
185 nothing to do with "Class::Container" or "Params::Validate" - any extra
186 entries like this are simply ignored, so you are free to put extra
187 information in the specifications as long as it doesn't overlap with
188 what "Class::Container" or "Params::Validate" are looking for.
189
190 $self->create_delayed_object()
191
192 If a contained object was declared with "delayed => 1", use this method
193 to create an instance of the object. Note that this is an object
194 method, not a class method:
195
196 my $foo = $self->create_delayed_object('foo', ...); # YES!
197 my $foo = __PACKAGE__->create_delayed_object('foo', ...); # NO!
198
199 The first argument should be a key passed to the "contained_objects()"
200 method. Any additional arguments will be passed to the "new()" method
201 of the object being created, overriding any parameters previously
202 passed to the container class constructor. (Could I possibly be more
203 alliterative? Veni, vedi, vici.)
204
205 $self->delayed_object_params($name, [params])
206
207 Allows you to adjust the parameters that will be used to create any
208 delayed objects in the future. The first argument specifies the "name"
209 of the object, and any additional arguments are key-value pairs that
210 will become parameters to the delayed object.
211
212 When called with only a $name argument and no list of parameters to
213 set, returns a hash reference containing the parameters that will be
214 passed when creating objects of this type.
215
216 $self->delayed_object_class($name)
217
218 Returns the class that will be used when creating delayed objects of
219 the given name. Use this sparingly - in most situations you shouldn't
220 care what the class is.
221
222 __PACKAGE__->decorates()
223
224 Version 0.09 of Class::Container added [as yet experimental] support
225 for so-called "decorator" relationships, using the term as defined in
226 Design Patterns by Gamma, et al. (the Gang of Four book). To declare a
227 class as a decorator of another class, simply set @ISA to the class
228 which will be decorated, and call the decorator class's "decorates()"
229 method.
230
231 Internally, this will ensure that objects are instantiated as decora‐
232 tors. This means that you can mix & match extra add-on functionality
233 classes much more easily.
234
235 In the current implementation, if only a single decoration is used on
236 an object, it will be instantiated as a simple subclass, thus avoiding
237 a layer of indirection.
238
239 $self->validation_spec()
240
241 Returns a hash reference suitable for passing to the "Params::Validate"
242 "validate" function. Does not include any arguments that can be passed
243 to contained objects.
244
245 $class->allowed_params(\%args)
246
247 Returns a hash reference of every parameter this class will accept,
248 including parameters it will pass on to its own contained objects. The
249 keys are the parameter names, and the values are their corresponding
250 specifications from their "valid_params()" definitions. If a parameter
251 is used by both the current object and one of its contained objects,
252 the specification returned will be from the container class, not the
253 contained.
254
255 Because the parameters accepted by "new()" can vary based on the param‐
256 eters passed to "new()", you can pass any parameters to the
257 "allowed_params()" method too, ensuring that the hash you get back is
258 accurate.
259
260 $self->container()
261
262 Returns the object that created you. This is remembered by storing a
263 reference to that object, so we use the "Scalar::Utils" "weakref()"
264 function to avoid persistent circular references that would cause mem‐
265 ory leaks. If you don't have "Scalar::Utils" installed, we don't make
266 these references in the first place, and calling "container()" will
267 result in a fatal error.
268
269 If you weren't created by another object via "Class::Container", "con‐
270 tainer()" returns "undef".
271
272 In most cases you shouldn't care what object created you, so use this
273 method sparingly.
274
275 $object->show_containers
276
277 $package->show_containers
278
279 This method returns a string meant to describe the containment rela‐
280 tionships among classes. You should not depend on the specific format‐
281 ting of the string, because I may change things in a future release to
282 make it prettier.
283
284 For example, the HTML::Mason code returns the following when you do
285 "$interp->show_containers":
286
287 HTML::Mason::Interp=HASH(0x238944)
288 resolver -> HTML::Mason::Resolver::File
289 compiler -> HTML::Mason::Compiler::ToObject
290 lexer -> HTML::Mason::Lexer
291 request -> HTML::Mason::Request (delayed)
292 buffer -> HTML::Mason::Buffer (delayed)
293
294 Currently, containment is shown by indentation, so the Interp object
295 contains a resolver and a compiler, and a delayed request (or several
296 delayed requests). The compiler contains a lexer, and each request
297 contains a delayed buffer (or several delayed buffers).
298
299 $object->dump_parameters
300
301 Returns a hash reference containing a set of parameters that should be
302 sufficient to re-create the given object using its class's "new()"
303 method. This is done by fetching the current value for each declared
304 parameter (i.e. looking in $object for hash entries of the same name),
305 then recursing through all contained objects and doing the same.
306
307 A few words of caution here. First, the dumped parameters represent
308 the current state of the object, not the state when it was originally
309 created.
310
311 Second, a class's declared parameters may not correspond exactly to its
312 data members, so it might not be possible to recover the former from
313 the latter. If it's possible but requires some manual fudging, you can
314 override this method in your class, something like so:
315
316 sub dump_parameters {
317 my $self = shift;
318 my $dump = $self->SUPER::dump_parameters();
319
320 # Perform fudgery
321 $dump->{incoming} = $self->{_private};
322 delete $dump->{superfluous};
323 return $dump;
324 }
325
327 Params::Validate
328
330 Originally by Ken Williams <ken@mathforum.org> and Dave Rolsky
331 <autarch@urth.org> for the HTML::Mason project. Important feedback
332 contributed by Jonathan Swartz <swartz@pobox.com>. Extended by Ken
333 Williams for the AI::Categorizer project.
334
335 Currently maintained by Ken Williams.
336
338 This program is free software; you can redistribute it and/or modify it
339 under the same terms as Perl itself.
340
341
342
343perl v5.8.8 2005-01-23 Class::Container(3)