version 1, including all changes.
.
Rev |
Author |
# |
Line |
1 |
perry |
1 |
PERLBOT |
|
|
2 |
!!!PERLBOT |
|
|
3 |
NAME |
|
|
4 |
DESCRIPTION |
|
|
5 |
OO SCALING TIPS |
|
|
6 |
INSTANCE VARIABLES |
|
|
7 |
SCALAR INSTANCE VARIABLES |
|
|
8 |
INSTANCE VARIABLE INHERITANCE |
|
|
9 |
OBJECT RELATIONSHIPS |
|
|
10 |
OVERRIDING SUPERCLASS METHODS |
|
|
11 |
USING RELATIONSHIP WITH SDBM |
|
|
12 |
THINKING OF CODE REUSE |
|
|
13 |
CLASS CONTEXT AND THE OBJECT |
|
|
14 |
INHERITING A CONSTRUCTOR |
|
|
15 |
DELEGATION |
|
|
16 |
---- |
|
|
17 |
!!NAME |
|
|
18 |
|
|
|
19 |
|
|
|
20 |
perlbot - Bag'o Object Tricks (the BOT ) |
|
|
21 |
!!DESCRIPTION |
|
|
22 |
|
|
|
23 |
|
|
|
24 |
The following collection of tricks and hints is intended to |
|
|
25 |
whet curious appetites about such things as the use of |
|
|
26 |
instance variables and the mechanics of object and class |
|
|
27 |
relationships. The reader is encouraged to consult relevant |
|
|
28 |
textbooks for discussion of Object Oriented definitions and |
|
|
29 |
methodology. This is not intended as a tutorial for |
|
|
30 |
object-oriented programming or as a comprehensive guide to |
|
|
31 |
Perl's object oriented features, nor should it be construed |
|
|
32 |
as a style guide. |
|
|
33 |
|
|
|
34 |
|
|
|
35 |
The Perl motto still holds: There's more than one way to do |
|
|
36 |
it. |
|
|
37 |
!!OO SCALING TIPS |
|
|
38 |
|
|
|
39 |
|
|
|
40 |
1 |
|
|
41 |
|
|
|
42 |
|
|
|
43 |
Do not attempt to verify the type of $self. That'll |
|
|
44 |
break if the class is inherited, when the type of |
|
|
45 |
$self is valid but its package isn't what you |
|
|
46 |
expect. See rule 5. |
|
|
47 |
|
|
|
48 |
|
|
|
49 |
2 |
|
|
50 |
|
|
|
51 |
|
|
|
52 |
If an object-oriented ( OO ) or |
|
|
53 |
indirect-object ( IO ) syntax was used, then |
|
|
54 |
the object is probably the correct type and there's no need |
|
|
55 |
to become paranoid about it. Perl isn't a paranoid language |
|
|
56 |
anyway. If people subvert the OO or |
|
|
57 |
IO syntax then they probably know what |
|
|
58 |
they're doing and you should let them do it. See rule |
|
|
59 |
1. |
|
|
60 |
|
|
|
61 |
|
|
|
62 |
3 |
|
|
63 |
|
|
|
64 |
|
|
|
65 |
Use the two-argument form of ''bless()''. Let a subclass |
|
|
66 |
use your constructor. See `` INHERITING A |
|
|
67 |
CONSTRUCTOR ''. |
|
|
68 |
|
|
|
69 |
|
|
|
70 |
4 |
|
|
71 |
|
|
|
72 |
|
|
|
73 |
The subclass is allowed to know things about its immediate |
|
|
74 |
superclass, the superclass is allowed to know nothing about |
|
|
75 |
a subclass. |
|
|
76 |
|
|
|
77 |
|
|
|
78 |
5 |
|
|
79 |
|
|
|
80 |
|
|
|
81 |
Don't be trigger happy with inheritance. A ``using'', |
|
|
82 |
``containing'', or ``delegation'' relationship (some sort of |
|
|
83 |
aggregation, at least) is often more appropriate. See `` |
|
|
84 |
OBJECT RELATIONSHIPS '', `` USING |
|
|
85 |
RELATIONSHIP WITH SDBM '', and `` |
|
|
86 |
DELEGATION ''. |
|
|
87 |
|
|
|
88 |
|
|
|
89 |
6 |
|
|
90 |
|
|
|
91 |
|
|
|
92 |
The object is the namespace. Make package globals accessible |
|
|
93 |
via the object. This will remove the guess work about the |
|
|
94 |
symbol's home package. See `` CLASS CONTEXT AND THE |
|
|
95 |
OBJECT ''. |
|
|
96 |
|
|
|
97 |
|
|
|
98 |
7 |
|
|
99 |
|
|
|
100 |
|
|
|
101 |
IO syntax is certainly less noisy, but it is |
|
|
102 |
also prone to ambiguities that can cause difficult-to-find |
|
|
103 |
bugs. Allow people to use the sure-thing OO |
|
|
104 |
syntax, even if you don't like it. |
|
|
105 |
|
|
|
106 |
|
|
|
107 |
8 |
|
|
108 |
|
|
|
109 |
|
|
|
110 |
Do not use function-call syntax on a method. You're going to |
|
|
111 |
be bitten someday. Someone might move that method into a |
|
|
112 |
superclass and your code will be broken. On top of that |
|
|
113 |
you're feeding the paranoia in rule 2. |
|
|
114 |
|
|
|
115 |
|
|
|
116 |
9 |
|
|
117 |
|
|
|
118 |
|
|
|
119 |
Don't assume you know the home package of a method. You're |
|
|
120 |
making it difficult for someone to override that method. See |
|
|
121 |
`` THINKING OF CODE REUSE ''. |
|
|
122 |
!!INSTANCE VARIABLES |
|
|
123 |
|
|
|
124 |
|
|
|
125 |
An anonymous array or anonymous hash can be used to hold |
|
|
126 |
instance variables. Named parameters are also |
|
|
127 |
demonstrated. |
|
|
128 |
|
|
|
129 |
|
|
|
130 |
package Foo; |
|
|
131 |
sub new { |
|
|
132 |
my $type = shift; |
|
|
133 |
my %params = @_; |
|
|
134 |
my $self = {}; |
|
|
135 |
$self- |
|
|
136 |
package Bar; |
|
|
137 |
sub new { |
|
|
138 |
my $type = shift; |
|
|
139 |
my %params = @_; |
|
|
140 |
my $self = [[]; |
|
|
141 |
$self- |
|
|
142 |
package main; |
|
|
143 |
$a = Foo- |
|
|
144 |
$b = Bar- |
|
|
145 |
!!SCALAR INSTANCE VARIABLES |
|
|
146 |
|
|
|
147 |
|
|
|
148 |
An anonymous scalar can be used when only one instance |
|
|
149 |
variable is needed. |
|
|
150 |
|
|
|
151 |
|
|
|
152 |
package Foo; |
|
|
153 |
sub new { |
|
|
154 |
my $type = shift; |
|
|
155 |
my $self; |
|
|
156 |
$self = shift; |
|
|
157 |
bless $self, $type; |
|
|
158 |
} |
|
|
159 |
package main; |
|
|
160 |
$a = Foo- |
|
|
161 |
!!INSTANCE VARIABLE INHERITANCE |
|
|
162 |
|
|
|
163 |
|
|
|
164 |
This example demonstrates how one might inherit instance |
|
|
165 |
variables from a superclass for inclusion in the new class. |
|
|
166 |
This requires calling the superclass's constructor and |
|
|
167 |
adding one's own instance variables to the new |
|
|
168 |
object. |
|
|
169 |
|
|
|
170 |
|
|
|
171 |
package Bar; |
|
|
172 |
sub new { |
|
|
173 |
my $type = shift; |
|
|
174 |
my $self = {}; |
|
|
175 |
$self- |
|
|
176 |
package Foo; |
|
|
177 |
@ISA = qw( Bar ); |
|
|
178 |
sub new { |
|
|
179 |
my $type = shift; |
|
|
180 |
my $self = Bar- |
|
|
181 |
package main; |
|
|
182 |
$a = Foo- |
|
|
183 |
!!OBJECT RELATIONSHIPS |
|
|
184 |
|
|
|
185 |
|
|
|
186 |
The following demonstrates how one might implement |
|
|
187 |
``containing'' and ``using'' relationships between |
|
|
188 |
objects. |
|
|
189 |
|
|
|
190 |
|
|
|
191 |
package Bar; |
|
|
192 |
sub new { |
|
|
193 |
my $type = shift; |
|
|
194 |
my $self = {}; |
|
|
195 |
$self- |
|
|
196 |
package Foo; |
|
|
197 |
sub new { |
|
|
198 |
my $type = shift; |
|
|
199 |
my $self = {}; |
|
|
200 |
$self- |
|
|
201 |
package main; |
|
|
202 |
$a = Foo- |
|
|
203 |
!!OVERRIDING SUPERCLASS METHODS |
|
|
204 |
|
|
|
205 |
|
|
|
206 |
The following example demonstrates how to override a |
|
|
207 |
superclass method and then call the overridden method. The |
|
|
208 |
__SUPER__ pseudo-class allows the |
|
|
209 |
programmer to call an overridden superclass method without |
|
|
210 |
actually knowing where that method is defined. |
|
|
211 |
|
|
|
212 |
|
|
|
213 |
package Buz; |
|
|
214 |
sub goo { print |
|
|
215 |
package Bar; @ISA = qw( Buz ); |
|
|
216 |
sub google { print |
|
|
217 |
package Baz; |
|
|
218 |
sub mumble { print |
|
|
219 |
package Foo; |
|
|
220 |
@ISA = qw( Bar Baz ); |
|
|
221 |
sub new { |
|
|
222 |
my $type = shift; |
|
|
223 |
bless [[], $type; |
|
|
224 |
} |
|
|
225 |
sub grr { print |
|
|
226 |
package main; |
|
|
227 |
$foo = Foo- |
|
|
228 |
!!USING RELATIONSHIP WITH SDBM |
|
|
229 |
|
|
|
230 |
|
|
|
231 |
This example demonstrates an interface for the |
|
|
232 |
SDBM class. This creates a ``using'' |
|
|
233 |
relationship between the SDBM class and the |
|
|
234 |
new class Mydbm. |
|
|
235 |
|
|
|
236 |
|
|
|
237 |
package Mydbm; |
|
|
238 |
require SDBM_File; |
|
|
239 |
require Tie::Hash; |
|
|
240 |
@ISA = qw( Tie::Hash ); |
|
|
241 |
sub TIEHASH { |
|
|
242 |
my $type = shift; |
|
|
243 |
my $ref = SDBM_File- |
|
|
244 |
package main; |
|
|
245 |
use Fcntl qw( O_RDWR O_CREAT ); |
|
|
246 |
tie %foo, |
|
|
247 |
tie %bar, |
|
|
248 |
!!THINKING OF CODE REUSE |
|
|
249 |
|
|
|
250 |
|
|
|
251 |
One strength of Object-Oriented languages is the ease with |
|
|
252 |
which old code can use new code. The following examples will |
|
|
253 |
demonstrate first how one can hinder code reuse and then how |
|
|
254 |
one can promote code reuse. |
|
|
255 |
|
|
|
256 |
|
|
|
257 |
This first example illustrates a class which uses a |
|
|
258 |
fully-qualified method call to access the ``private'' method |
|
|
259 |
''BAZ ()''. The second example will show |
|
|
260 |
that it is impossible to override the ''BAZ |
|
|
261 |
()'' method. |
|
|
262 |
|
|
|
263 |
|
|
|
264 |
package FOO; |
|
|
265 |
sub new { |
|
|
266 |
my $type = shift; |
|
|
267 |
bless {}, $type; |
|
|
268 |
} |
|
|
269 |
sub bar { |
|
|
270 |
my $self = shift; |
|
|
271 |
$self- |
|
|
272 |
package FOO::private; |
|
|
273 |
sub BAZ { |
|
|
274 |
print |
|
|
275 |
package main; |
|
|
276 |
$a = FOO- |
|
|
277 |
Now we try to override the ''BAZ ()'' method. We would like ''FOO::bar()'' to call ''GOOP::BAZ ()'', but this cannot happen because ''FOO::bar()'' explicitly calls ''FOO::private::BAZ()''. |
|
|
278 |
|
|
|
279 |
|
|
|
280 |
package FOO; |
|
|
281 |
sub new { |
|
|
282 |
my $type = shift; |
|
|
283 |
bless {}, $type; |
|
|
284 |
} |
|
|
285 |
sub bar { |
|
|
286 |
my $self = shift; |
|
|
287 |
$self- |
|
|
288 |
package FOO::private; |
|
|
289 |
sub BAZ { |
|
|
290 |
print |
|
|
291 |
package GOOP; |
|
|
292 |
@ISA = qw( FOO ); |
|
|
293 |
sub new { |
|
|
294 |
my $type = shift; |
|
|
295 |
bless {}, $type; |
|
|
296 |
} |
|
|
297 |
sub BAZ { |
|
|
298 |
print |
|
|
299 |
package main; |
|
|
300 |
$a = GOOP- |
|
|
301 |
To create reusable code we must modify class FOO , flattening class FOO::private. The next example shows a reusable class FOO which allows the method ''GOOP::BAZ ()'' to be used in place of ''FOO::BAZ ()''. |
|
|
302 |
|
|
|
303 |
|
|
|
304 |
package FOO; |
|
|
305 |
sub new { |
|
|
306 |
my $type = shift; |
|
|
307 |
bless {}, $type; |
|
|
308 |
} |
|
|
309 |
sub bar { |
|
|
310 |
my $self = shift; |
|
|
311 |
$self- |
|
|
312 |
sub BAZ { |
|
|
313 |
print |
|
|
314 |
package GOOP; |
|
|
315 |
@ISA = qw( FOO ); |
|
|
316 |
sub new { |
|
|
317 |
my $type = shift; |
|
|
318 |
bless {}, $type; |
|
|
319 |
} |
|
|
320 |
sub BAZ { |
|
|
321 |
print |
|
|
322 |
package main; |
|
|
323 |
$a = GOOP- |
|
|
324 |
!!CLASS CONTEXT AND THE OBJECT |
|
|
325 |
|
|
|
326 |
|
|
|
327 |
Use the object to solve package and class context problems. |
|
|
328 |
Everything a method needs should be available via the object |
|
|
329 |
or should be passed as a parameter to the |
|
|
330 |
method. |
|
|
331 |
|
|
|
332 |
|
|
|
333 |
A class will sometimes have static or global data to be used |
|
|
334 |
by the methods. A subclass may want to override that data |
|
|
335 |
and replace it with new data. When this happens the |
|
|
336 |
superclass may not know how to find the new copy of the |
|
|
337 |
data. |
|
|
338 |
|
|
|
339 |
|
|
|
340 |
This problem can be solved by using the object to define the |
|
|
341 |
context of the method. Let the method look in the object for |
|
|
342 |
a reference to the data. The alternative is to force the |
|
|
343 |
method to go hunting for the data (``Is it in my class, or |
|
|
344 |
in a subclass? Which subclass?''), and this can be |
|
|
345 |
inconvenient and will lead to hackery. It is better just to |
|
|
346 |
let the object tell the method where that data is |
|
|
347 |
located. |
|
|
348 |
|
|
|
349 |
|
|
|
350 |
package Bar; |
|
|
351 |
%fizzle = ( 'Password' = |
|
|
352 |
sub new { |
|
|
353 |
my $type = shift; |
|
|
354 |
my $self = {}; |
|
|
355 |
$self- |
|
|
356 |
sub enter { |
|
|
357 |
my $self = shift; |
|
|
358 |
# Don't try to guess if we should use %Bar::fizzle |
|
|
359 |
# or %Foo::fizzle. The object already knows which |
|
|
360 |
# we should use, so just ask it. |
|
|
361 |
# |
|
|
362 |
my $fizzle = $self- |
|
|
363 |
print |
|
|
364 |
package Foo; |
|
|
365 |
@ISA = qw( Bar ); |
|
|
366 |
%fizzle = ( 'Password' = |
|
|
367 |
sub new { |
|
|
368 |
my $type = shift; |
|
|
369 |
my $self = Bar- |
|
|
370 |
package main; |
|
|
371 |
$a = Bar- |
|
|
372 |
!!INHERITING A CONSTRUCTOR |
|
|
373 |
|
|
|
374 |
|
|
|
375 |
An inheritable constructor should use the second form of |
|
|
376 |
''bless()'' which allows blessing directly into a |
|
|
377 |
specified class. Notice in this example that the object will |
|
|
378 |
be a BAR not a FOO , even |
|
|
379 |
though the constructor is in class FOO |
|
|
380 |
. |
|
|
381 |
|
|
|
382 |
|
|
|
383 |
package FOO; |
|
|
384 |
sub new { |
|
|
385 |
my $type = shift; |
|
|
386 |
my $self = {}; |
|
|
387 |
bless $self, $type; |
|
|
388 |
} |
|
|
389 |
sub baz { |
|
|
390 |
print |
|
|
391 |
package BAR; |
|
|
392 |
@ISA = qw(FOO); |
|
|
393 |
sub baz { |
|
|
394 |
print |
|
|
395 |
package main; |
|
|
396 |
$a = BAR- |
|
|
397 |
!!DELEGATION |
|
|
398 |
|
|
|
399 |
|
|
|
400 |
Some classes, such as SDBM_File, cannot be effectively |
|
|
401 |
subclassed because they create foreign objects. Such a class |
|
|
402 |
can be extended with some sort of aggregation technique such |
|
|
403 |
as the ``using'' relationship mentioned earlier or by |
|
|
404 |
delegation. |
|
|
405 |
|
|
|
406 |
|
|
|
407 |
The following example demonstrates delegation using an |
|
|
408 |
''AUTOLOAD ()'' function to perform |
|
|
409 |
message-forwarding. This will allow the Mydbm object to |
|
|
410 |
behave exactly like an SDBM_File object. The Mydbm class |
|
|
411 |
could now extend the behavior by adding custom |
|
|
412 |
''FETCH ()'' and ''STORE |
|
|
413 |
()'' methods, if this is desired. |
|
|
414 |
|
|
|
415 |
|
|
|
416 |
package Mydbm; |
|
|
417 |
require SDBM_File; |
|
|
418 |
require Tie::Hash; |
|
|
419 |
@ISA = qw(Tie::Hash); |
|
|
420 |
sub TIEHASH { |
|
|
421 |
my $type = shift; |
|
|
422 |
my $ref = SDBM_File- |
|
|
423 |
sub AUTOLOAD { |
|
|
424 |
my $self = shift; |
|
|
425 |
# The Perl interpreter places the name of the |
|
|
426 |
# message in a variable called $AUTOLOAD. |
|
|
427 |
# DESTROY messages should never be propagated. |
|
|
428 |
return if $AUTOLOAD =~ /::DESTROY$/; |
|
|
429 |
# Remove the package name. |
|
|
430 |
$AUTOLOAD =~ s/^Mydbm:://; |
|
|
431 |
# Pass the message to the delegate. |
|
|
432 |
$self- |
|
|
433 |
package main; |
|
|
434 |
use Fcntl qw( O_RDWR O_CREAT ); |
|
|
435 |
tie %foo, |
|
|
436 |
---- |