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
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

METHODS

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

RESOURCES

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

SEE ALSO

488       Class::ISA
489
490       Class::Trigger
491
492       Aspect
493

AUTHOR

495       Aristotle Pagaltzis <pagaltzis@gmx.de>
496
497       Chris Winters
498
500       This documentation is copyright (c) 2002-2004 Chris Winters.
501
502       This software is copyright (c) 2021 by Aristotle Pagaltzis.
503
504       This is free software; you can redistribute it and/or modify it under
505       the same terms as the Perl 5 programming language system itself.
506
507
508
509perl v5.36.0                      2022-08-18              Class::Observable(3)
Impressum