1Class::Observable(3)  User Contributed Perl Documentation Class::Observable(3)
2
3
4

NAME

6       Class::Observable - Allow other classes and objects to respond to
7       events in yours
8

SYNOPSIS

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

DESCRIPTION

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

USER GUIDE

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 notify_observers().
161
162       As noted above, whether the observed item is a class or object does not
163       matter -- the behavior is the same. The difference comes in determining
164       which observers are to be notified:
165
166       •   If the observed item is a class, all objects instantiated from that
167           class will use these observers. In addition, all subclasses and
168           objects instantiated from the subclasses will use these observers.
169
170       •   If the observed item is an object, only that particular object will
171           use its observers. Once it falls out of scope then the observers
172           will no longer be available. (See "Observable Objects and DESTROY"
173           below.)
174
175       Whichever you chose, your documentation should make clear which type of
176       observed item observers can expect.
177
178       So given the following example:
179
180        BEGIN {
181            package Foo;
182            use parent qw( Class::Observable );
183            sub new { return bless( {}, $_[0] ) }
184            sub yodel { $_[0]->notify_observers }
185
186            package Baz;
187            use parent qw( Foo );
188            sub yell { $_[0]->notify_observers }
189        }
190
191        sub observer_a { print "Observation A from [$_[0]]\n" }
192        sub observer_b { print "Observation B from [$_[0]]\n" }
193        sub observer_c { print "Observation C from [$_[0]]\n" }
194
195        Foo->add_observer( \&observer_a );
196        Baz->add_observer( \&observer_b );
197
198        my $foo = Foo->new;
199        print "Yodeling...\n";
200        $foo->yodel;
201
202        my $baz_a = Baz->new;
203        print "Yelling A...\n";
204        $baz_a->yell;
205
206        my $baz_b = Baz->new;
207        $baz_b->add_observer( \&observer_c );
208        print "Yelling B...\n";
209        $baz_b->yell;
210
211       You would see something like
212
213        Yodeling...
214        Observation A from [Foo=HASH(0x80f7acc)]
215        Yelling A...
216        Observation B from [Baz=HASH(0x815c2b4)]
217        Observation A from [Baz=HASH(0x815c2b4)]
218        Yelling B...
219        Observation C from [Baz=HASH(0x815c344)]
220        Observation B from [Baz=HASH(0x815c344)]
221        Observation A from [Baz=HASH(0x815c344)]
222
223       And since "Bar" is a child of "Foo" and each has one class-level
224       observer, running either:
225
226        my @observers = Baz->get_observers();
227        my @observers = $baz_a->get_observers();
228
229       would return a two-item list. The first item would be the "observer_b"
230       code reference, the second the "observer_a" code reference. Running:
231
232        my @observers = $baz_b->get_observers();
233
234       would return a three-item list, including the observer for that
235       specific object ("observer_c" coderef) as well as from its class (Baz)
236       and the parent (Foo) of its class.
237
238   Observers
239       There are three types of observers: classes, objects, and subroutines.
240       All three respond to events when notify_observers() is called from an
241       observable item. The differences among the three are are:
242
243       •   A class or object observer must implement a method update() which
244           is called when a state-change occurs. The name of the subroutine
245           observer is irrelevant.
246
247       •   A class or object observer must take at least two arguments: itself
248           and the observed item. The subroutine observer is obligated to take
249           only one argument, the observed item.
250
251           Both types of observers may also take an action name and a hashref
252           of parameters as optional arguments. Whether these are used depends
253           on the observed item.
254
255       •   Object observers can maintain state between responding to
256           observations.
257
258       Examples:
259
260       Subroutine observer:
261
262        sub respond {
263            my ( $item, $action, $params ) = @_;
264            return unless ( $action eq 'update' );
265            # ...
266        }
267        $observable->add_observer( \&respond );
268
269       Class observer:
270
271        package My::ObserverC;
272
273        sub update {
274            my ( $class, $item, $action, $params ) = @_;
275            return unless ( $action eq 'update' );
276            # ...
277        }
278
279       Object observer:
280
281        package My::ObserverO;
282
283        sub new {
284            my ( $class, $type ) = @_;
285            return bless ( { type => $type }, $class );
286        }
287
288        sub update {
289            my ( $self, $item, $action, $params ) = @_;
290            return unless ( $action eq $self->{type} );
291            # ...
292        }
293
294   Observable Objects and DESTROY
295       This class has a "DESTROY" method which must run when an instance of an
296       observable class goes out of scope in order to clean up the observers
297       added to that instance.
298
299       If there is no other destructor in the inheritance tree, this will end
300       up happening naturally and everything will be fine.
301
302       If it does not get called, then the list of observers will leak (which
303       also prevents the observers in it from being garbage-collected) and may
304       become associated with a different instance created later at the same
305       memory address as a previous instance.
306
307       This may happen if a class needs its own "DESTROY" method when it also
308       wants to inherit from Class::Observer (even indirectly!), because perl
309       only invokes the single nearest inherited "DESTROY".
310
311       The most straightforward (but maybe not best) way to ensure that the
312       destructor is called is to do something like this:
313
314         # in My::Class
315         sub DESTROY {
316             # ...
317             $self->Class::Observable::DESTROY;
318             # ...
319         }
320
321       A better way may be to to write all destructors in your class hierarchy
322       with the expectation that all of them will be called (which would
323       usually be preferred anyway) and then enforcing that expectation by
324       writing all of them as follows:
325
326         use mro;
327         sub DESTROY {
328             # ...
329             $self->maybe::next::method;
330             # ...
331         }
332
333       (Perl being Perl, of course, there are many other ways to go about
334       this.)
335

METHODS

337       notify_observers( [ $action, @params ] )
338
339       Called from the observed item, this method sends a message to all
340       observers that a state-change has occurred. The observed item can
341       optionally include additional information about the type of change that
342       has occurred and any additional parameters @params which get passed
343       along to each observer. The observed item should indicate in its API
344       what information will be passed along to the observers in $action and
345       @params.
346
347       Returns: Nothing
348
349       Example:
350
351        sub remove {
352            my ( $self ) = @_;
353            eval { $self->_remove_item_from_datastore };
354            if ( $@ ) {
355                $self->notify_observers( 'remove-fail', error_message => $@ );
356            } else {
357                $self->notify_observers( 'remove' );
358            }
359        }
360
361       add_observer( @observers )
362
363       Adds the one or more observers (@observer) to the observed item. Each
364       observer can be a class name, object or subroutine -- see "Types of
365       Observers".
366
367       Returns: The number of observers now observing the item.
368
369       Example:
370
371        # Add a salary check (as a subroutine observer) for a particular
372        # person
373        my $person = Person->fetch( 3843857 );
374        $person->add_observer( \&salary_check );
375
376        # Add a salary check (as a class observer) for all people
377        Person->add_observer( 'Validate::Salary' );
378
379        # Add a salary check (as an object observer) for all people
380        my $salary_policy = Company::Policy::Salary->new( 'pretax' );
381        Person->add_observer( $salary_policy );
382
383       delete_observer( @observers )
384
385       Removes the one or more observers (@observer) from the observed item.
386       Each observer can be a class name, object or subroutine -- see "Types
387       of Observers".
388
389       Note that this only deletes each observer from the observed item
390       itself. It does not remove observer from any parent classes. Therefore,
391       if an observer is not registered directly with the observed item
392       nothing will be removed.
393
394       Returns: The number of observers now observing the item.
395
396       Examples:
397
398        # Remove a class observer from an object
399        $person->delete_observer( 'Lech::Ogler' );
400
401        # Remove an object observer from a class
402        Person->delete_observer( $salary_policy );
403
404       delete_all_observers()
405
406       Removes all observers from the observed item.
407
408       Note that this only deletes observers registered directly with the
409       observed item. It does not clear out observers from any parent classes.
410
411       WARNING: This method was renamed from "delete_observers". The
412       "delete_observers" call still works but is deprecated and will
413       eventually be removed.
414
415       Returns: The number of observers removed.
416
417       Example:
418
419        Person->delete_all_observers();
420
421       get_observers()
422
423       Returns all observers for an observed item, as well as the observers
424       for its class and parents as applicable. See "Observable Classes and
425       Objects" for more information.
426
427       Returns: list of observers.
428
429       Example:
430
431        my @observers = Person->get_observers;
432        foreach my $o ( @observers ) {
433            print "Observer is a: ";
434            print "Class"      unless ( ref $o );
435            print "Subroutine" if ( ref $o eq 'CODE' );
436            print "Object"     if ( ref $o and ref $o ne 'CODE' );
437            print "\n";
438        }
439
440       copy_observers( $copy_to_observable )
441
442       Copies all observers from one observed item to another. We get all
443       observers from the source, including the observers of parents. (Behind
444       the scenes we just use get_observers(), so read that for what we copy.)
445
446       We make no effort to ensure we don't copy an observer that's already
447       watching the object we're copying to. If this happens you will appear
448       to get duplicate observations. (But it shouldn't happen often, if
449       ever.)
450
451       Returns: number of observers copied
452
453       Example:
454
455        # Copy all observers of the 'Person' class to also observe the
456        # 'Address' class
457
458        Person->copy_observers( Address );
459
460        # Copy all observers of a $person to also observe a particular
461        # $address
462
463        $person->copy_observers( $address )
464
465       count_observers()
466
467       Counts the number of observers for an observed item, including ones
468       inherited from its class and/or parent classes. See "Observable Classes
469       and Objects" for more information.
470

RESOURCES

472       APIs for "java.util.Observable" and "java.util.Observer". (Docs below
473       are included with JDK 1.4 but have been consistent for some time.)
474
475       <http://java.sun.com/j2se/1.4/docs/api/java/util/Observable.html>
476
477       <http://java.sun.com/j2se/1.4/docs/api/java/util/Observer.html>
478
479       "Observer and Observable", Todd Sundsted,
480       <http://www.javaworld.com/javaworld/jw-10-1996/jw-10-howto_p.html>
481
482       "Java Tip 29: How to decouple the Observer/Observable object model",
483       Albert Lopez, <http://www.javaworld.com/javatips/jw-javatip29_p.html>
484

SEE ALSO

486       Class::ISA
487
488       Class::Trigger
489
490       Aspect
491

AUTHOR

493       Aristotle Pagaltzis <pagaltzis@gmx.de>
494
495       Chris Winters
496
498       This documentation is copyright (c) 2002-2004 Chris Winters.
499
500       This software 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.36.0                      2023-01-20              Class::Observable(3)
Impressum