1Class::Observable(3) User Contributed Perl Documentation Class::Observable(3)
2
3
4
6 Class::Observable - Allow other classes and objects to respond to
7 events in yours
8
10 # Define an observable class
11
12 package My::Object;
13
14 use parent qw( Class::Observable );
15
16 # Tell all classes/objects observing this object that a state-change
17 # has occurred
18
19 sub create {
20 my ( $self ) = @_;
21 eval { $self->_perform_create() };
22 if ( $@ ) {
23 My::Exception->throw( "Error saving: $@" );
24 }
25 $self->notify_observers();
26 }
27
28 # Same thing, except make the type of change explicit and pass
29 # arguments.
30
31 sub edit {
32 my ( $self ) = @_;
33 my %old_values = $self->extract_values;
34 eval { $self->_perform_edit() };
35 if ( $@ ) {
36 My::Exception->throw( "Error saving: $@" );
37 }
38 $self->notify_observers( 'edit', old_values => \%old_values );
39 }
40
41 # Define an observer
42
43 package My::Observer;
44
45 sub update {
46 my ( $class, $object, $action ) = @_;
47 unless ( $action ) {
48 warn "Cannot operation on [", $object->id, "] without action";
49 return;
50 }
51 $class->_on_save( $object ) if ( $action eq 'save' );
52 $class->_on_update( $object ) if ( $action eq 'update' );
53 }
54
55 # Register the observer class with all instances of the observable
56 # class
57
58 My::Object->add_observer( 'My::Observer' );
59
60 # Register the observer class with a single instance of the
61 # observable class
62
63 my $object = My::Object->new( 'foo' );
64 $object->add_observer( 'My::Observer' );
65
66 # Register an observer object the same way
67
68 my $observer = My::Observer->new( 'bar' );
69 My::Object->add_observer( $observer );
70 my $object = My::Object->new( 'foo' );
71 $object->add_observer( $observer );
72
73 # Register an observer using a subroutine
74
75 sub catch_observation { ... }
76
77 My::Object->add_observer( \&catch_observation );
78 my $object = My::Object->new( 'foo' );
79 $object->add_observer( \&catch_observation );
80
81 # Define the observable class as a parent and allow the observers to
82 # be used by the child
83
84 package My::Parent;
85
86 use strict;
87 use parent qw( Class::Observable );
88
89 sub prepare_for_bed {
90 my ( $self ) = @_;
91 $self->notify_observers( 'prepare_for_bed' );
92 }
93
94 sub brush_teeth {
95 my ( $self ) = @_;
96 $self->_brush_teeth( time => 45 );
97 $self->_floss_teeth( time => 30 );
98 $self->_gargle( time => 30 );
99 }
100
101 sub wash_face { ... }
102
103
104 package My::Child;
105
106 use strict;
107 use parent qw( My::Parent );
108
109 sub brush_teeth {
110 my ( $self ) = @_;
111 $self->_wet_toothbrush();
112 }
113
114 sub wash_face { return }
115
116 # Create a class-based observer
117
118 package My::ParentRules;
119
120 sub update {
121 my ( $item, $action ) = @_;
122 if ( $action eq 'prepare_for_bed' ) {
123 $item->brush_teeth;
124 $item->wash_face;
125 }
126 }
127
128 My::Parent->add_observer( __PACKAGE__ );
129
130 $parent->prepare_for_bed # brush, floss, gargle, and wash face
131 $child->prepare_for_bed # pretend to brush, pretend to wash face
132
134 If you have ever used Java, you may have run across the
135 "java.util.Observable" class and the "java.util.Observer" interface.
136 With them you can decouple an object from the one or more objects that
137 wish to be notified whenever particular events occur.
138
139 These events occur based on a contract with the observed item. They may
140 occur at the beginning, in the middle or end of a method. In addition,
141 the object knows that it is being observed. It just does not know how
142 many or what types of objects are doing the observing. It can therefore
143 control when the messages get sent to the obsevers.
144
145 The behavior of the observers is up to you. However, be aware that we
146 do not do any error handling from calls to the observers. If an
147 observer throws a "die", it will bubble up to the observed item and
148 require handling there. So be careful.
149
151 Throughout this documentation we refer to an 'observed item' or
152 'observable item'. This ambiguity refers to the fact that both a class
153 and an object can be observed. The behavior when notifying observers is
154 identical. The only difference comes in which observers are notified.
155 (See "Observable Classes and Objects" for more information.)
156
157 Observable Classes and Objects
158 The observable item does not need to implement any extra methods or
159 variables. Whenever it wants to let observers know about a state-change
160 or occurrence in the object, it just needs to call
161 "notify_observers()".
162
163 As noted above, whether the observed item is a class or object does not
164 matter -- the behavior is the same. The difference comes in determining
165 which observers are to be notified:
166
167 • If the observed item is a class, all objects instantiated from that
168 class will use these observers. In addition, all subclasses and
169 objects instantiated from the subclasses will use these observers.
170
171 • If the observed item is an object, only that particular object will
172 use its observers. Once it falls out of scope then the observers
173 will no longer be available. (See "Observable Objects and DESTROY"
174 below.)
175
176 Whichever you chose, your documentation should make clear which type of
177 observed item observers can expect.
178
179 So given the following example:
180
181 BEGIN {
182 package Foo;
183 use parent qw( Class::Observable );
184 sub new { return bless( {}, $_[0] ) }
185 sub yodel { $_[0]->notify_observers }
186
187 package Baz;
188 use parent qw( Foo );
189 sub yell { $_[0]->notify_observers }
190 }
191
192 sub observer_a { print "Observation A from [$_[0]]\n" }
193 sub observer_b { print "Observation B from [$_[0]]\n" }
194 sub observer_c { print "Observation C from [$_[0]]\n" }
195
196 Foo->add_observer( \&observer_a );
197 Baz->add_observer( \&observer_b );
198
199 my $foo = Foo->new;
200 print "Yodeling...\n";
201 $foo->yodel;
202
203 my $baz_a = Baz->new;
204 print "Yelling A...\n";
205 $baz_a->yell;
206
207 my $baz_b = Baz->new;
208 $baz_b->add_observer( \&observer_c );
209 print "Yelling B...\n";
210 $baz_b->yell;
211
212 You would see something like
213
214 Yodeling...
215 Observation A from [Foo=HASH(0x80f7acc)]
216 Yelling A...
217 Observation B from [Baz=HASH(0x815c2b4)]
218 Observation A from [Baz=HASH(0x815c2b4)]
219 Yelling B...
220 Observation C from [Baz=HASH(0x815c344)]
221 Observation B from [Baz=HASH(0x815c344)]
222 Observation A from [Baz=HASH(0x815c344)]
223
224 And since "Bar" is a child of "Foo" and each has one class-level
225 observer, running either:
226
227 my @observers = Baz->get_observers();
228 my @observers = $baz_a->get_observers();
229
230 would return a two-item list. The first item would be the "observer_b"
231 code reference, the second the "observer_a" code reference. Running:
232
233 my @observers = $baz_b->get_observers();
234
235 would return a three-item list, including the observer for that
236 specific object ("observer_c" coderef) as well as from its class (Baz)
237 and the parent (Foo) of its class.
238
239 Observers
240 There are three types of observers: classes, objects, and subroutines.
241 All three respond to events when "notify_observers()" is called from an
242 observable item. The differences among the three are are:
243
244 • A class or object observer must implement a method "update()" which
245 is called when a state-change occurs. The name of the subroutine
246 observer is irrelevant.
247
248 • A class or object observer must take at least two arguments: itself
249 and the observed item. The subroutine observer is obligated to take
250 only one argument, the observed item.
251
252 Both types of observers may also take an action name and a hashref
253 of parameters as optional arguments. Whether these are used depends
254 on the observed item.
255
256 • Object observers can maintain state between responding to
257 observations.
258
259 Examples:
260
261 Subroutine observer:
262
263 sub respond {
264 my ( $item, $action, $params ) = @_;
265 return unless ( $action eq 'update' );
266 # ...
267 }
268 $observable->add_observer( \&respond );
269
270 Class observer:
271
272 package My::ObserverC;
273
274 sub update {
275 my ( $class, $item, $action, $params ) = @_;
276 return unless ( $action eq 'update' );
277 # ...
278 }
279
280 Object observer:
281
282 package My::ObserverO;
283
284 sub new {
285 my ( $class, $type ) = @_;
286 return bless ( { type => $type }, $class );
287 }
288
289 sub update {
290 my ( $self, $item, $action, $params ) = @_;
291 return unless ( $action eq $self->{type} );
292 # ...
293 }
294
295 Observable Objects and DESTROY
296 This class has a "DESTROY" method which must run when an instance of an
297 observable class goes out of scope in order to clean up the observers
298 added to that instance.
299
300 If there is no other destructor in the inheritance tree, this will end
301 up happening naturally and everything will be fine.
302
303 If it does not get called, then the list of observers will leak (which
304 also prevents the observers in it from being garbage-collected) and may
305 become associated with a different instance created later at the same
306 memory address as a previous instance.
307
308 This may happen if a class needs its own "DESTROY" method when it also
309 wants to inherit from Class::Observer (even indirectly!), because perl
310 only invokes the single nearest inherited "DESTROY".
311
312 The most straightforward (but maybe not best) way to ensure that the
313 destructor is called is to do something like this:
314
315 # in My::Class
316 sub DESTROY {
317 # ...
318 $self->Class::Observable::DESTROY;
319 # ...
320 }
321
322 A better way may be to to write all destructors in your class hierarchy
323 with the expectation that all of them will be called (which would
324 usually be preferred anyway) and then enforcing that expectation by
325 writing all of them as follows:
326
327 use mro;
328 sub DESTROY {
329 # ...
330 $self->maybe::next::method;
331 # ...
332 }
333
334 (Perl being Perl, of course, there are many other ways to go about
335 this.)
336
338 notify_observers( [ $action, @params ] )
339
340 Called from the observed item, this method sends a message to all
341 observers that a state-change has occurred. The observed item can
342 optionally include additional information about the type of change that
343 has occurred and any additional parameters @params which get passed
344 along to each observer. The observed item should indicate in its API
345 what information will be passed along to the observers in $action and
346 @params.
347
348 Returns: Nothing
349
350 Example:
351
352 sub remove {
353 my ( $self ) = @_;
354 eval { $self->_remove_item_from_datastore };
355 if ( $@ ) {
356 $self->notify_observers( 'remove-fail', error_message => $@ );
357 }
358 else {
359 $self->notify_observers( 'remove' );
360 }
361 }
362
363 add_observer( @observers )
364
365 Adds the one or more observers (@observer) to the observed item. Each
366 observer can be a class name, object or subroutine -- see "Types of
367 Observers".
368
369 Returns: The number of observers now observing the item.
370
371 Example:
372
373 # Add a salary check (as a subroutine observer) for a particular
374 # person
375 my $person = Person->fetch( 3843857 );
376 $person->add_observer( \&salary_check );
377
378 # Add a salary check (as a class observer) for all people
379 Person->add_observer( 'Validate::Salary' );
380
381 # Add a salary check (as an object observer) for all people
382 my $salary_policy = Company::Policy::Salary->new( 'pretax' );
383 Person->add_observer( $salary_policy );
384
385 delete_observer( @observers )
386
387 Removes the one or more observers (@observer) from the observed item.
388 Each observer can be a class name, object or subroutine -- see "Types
389 of Observers".
390
391 Note that this only deletes each observer from the observed item
392 itself. It does not remove observer from any parent classes. Therefore,
393 if an observer is not registered directly with the observed item
394 nothing will be removed.
395
396 Returns: The number of observers now observing the item.
397
398 Examples:
399
400 # Remove a class observer from an object
401 $person->delete_observer( 'Lech::Ogler' );
402
403 # Remove an object observer from a class
404 Person->delete_observer( $salary_policy );
405
406 delete_all_observers()
407
408 Removes all observers from the observed item.
409
410 Note that this only deletes observers registered directly with the
411 observed item. It does not clear out observers from any parent classes.
412
413 WARNING: This method was renamed from "delete_observers". The
414 "delete_observers" call still works but is deprecated and will
415 eventually be removed.
416
417 Returns: The number of observers removed.
418
419 Example:
420
421 Person->delete_all_observers();
422
423 get_observers()
424
425 Returns all observers for an observed item, as well as the observers
426 for its class and parents as applicable. See "Observable Classes and
427 Objects" for more information.
428
429 Returns: list of observers.
430
431 Example:
432
433 my @observers = Person->get_observers;
434 foreach my $o ( @observers ) {
435 print "Observer is a: ";
436 print "Class" unless ( ref $o );
437 print "Subroutine" if ( ref $o eq 'CODE' );
438 print "Object" if ( ref $o and ref $o ne 'CODE' );
439 print "\n";
440 }
441
442 copy_observers( $copy_to_observable )
443
444 Copies all observers from one observed item to another. We get all
445 observers from the source, including the observers of parents. (Behind
446 the scenes we just use "get_observers()", so read that for what we
447 copy.)
448
449 We make no effort to ensure we don't copy an observer that's already
450 watching the object we're copying to. If this happens you will appear
451 to get duplicate observations. (But it shouldn't happen often, if
452 ever.)
453
454 Returns: number of observers copied
455
456 Example:
457
458 # Copy all observers of the 'Person' class to also observe the
459 # 'Address' class
460
461 Person->copy_observers( Address );
462
463 # Copy all observers of a $person to also observe a particular
464 # $address
465
466 $person->copy_observers( $address )
467
468 count_observers()
469
470 Counts the number of observers for an observed item, including ones
471 inherited from its class and/or parent classes. See "Observable Classes
472 and Objects" for more information.
473
475 APIs for "java.util.Observable" and "java.util.Observer". (Docs below
476 are included with JDK 1.4 but have been consistent for some time.)
477
478 <http://java.sun.com/j2se/1.4/docs/api/java/util/Observable.html>
479
480 <http://java.sun.com/j2se/1.4/docs/api/java/util/Observer.html>
481
482 "Observer and Observable", Todd Sundsted,
483 <http://www.javaworld.com/javaworld/jw-10-1996/jw-10-howto_p.html>
484
485 "Java Tip 29: How to decouple the Observer/Observable object model",
486 Albert Lopez, <http://www.javaworld.com/javatips/jw-javatip29_p.html>
487
489 Class::ISA
490
491 Class::Trigger
492
493 Aspect
494
496 Chris Winters <chris@cwinters.com>
497
499 This software is copyright (c) 2002-2004 Chris Winters. This software
500 is copyright (c) 2021 by Aristotle Pagaltzis.
501
502 This is free software; you can redistribute it and/or modify it under
503 the same terms as the Perl 5 programming language system itself.
504
505
506
507perl v5.34.0 2021-07-22 Class::Observable(3)