Class::Observable man page on Pidora

Man page or keyword search:  
man Server   31170 pages
apropos Keyword Search (all sections)
Output format
Pidora logo
[printable version]

Class::Observable(3)  User Contributed Perl Documentation Class::Observable(3)

NAME
       Class::Observable - Allow other classes and objects to respond to
       events in yours

SYNOPSIS
	 # Define an observable class

	 package My::Object;

	 use base qw( Class::Observable );

	 # Tell all classes/objects observing this object that a state-change
	 # has occurred

	 sub create {
	    my ( $self ) = @_;
	    eval { $self->_perform_create() };
	    if ( $@ ) {
		My::Exception->throw( "Error saving: $@" );
	    }
	    $self->notify_observers();
	 }

	 # Same thing, except make the type of change explicit and pass
	 # arguments.

	 sub edit {
	    my ( $self ) = @_;
	    my %old_values = $self->extract_values;
	    eval { $self->_perform_edit() };
	    if ( $@ ) {
		My::Exception->throw( "Error saving: $@" );
	    }
	    $self->notify_observers( 'edit', old_values => \%old_values );
	 }

	 # Define an observer

	 package My::Observer;

	 sub update {
	    my ( $class, $object, $action ) = @_;
	    unless ( $action ) {
		warn "Cannot operation on [", $object->id, "] without action";
		return;
	    }
	    $class->_on_save( $object )	  if ( $action eq 'save' );
	    $class->_on_update( $object ) if ( $action eq 'update' );
	 }

	 # Register the observer class with all instances of the observable
	 # class

	 My::Object->add_observer( 'My::Observer' );

	 # Register the observer class with a single instance of the
	 # observable class

	 my $object = My::Object->new( 'foo' );
	 $object->add_observer( 'My::Observer' );

	 # Register an observer object the same way

	 my $observer = My::Observer->new( 'bar' );
	 My::Object->add_observer( $observer );
	 my $object = My::Object->new( 'foo' );
	 $object->add_observer( $observer );

	 # Register an observer using a subroutine

	 sub catch_observation { ... }

	 My::Object->add_observer( \&catch_observation );
	 my $object = My::Object->new( 'foo' );
	 $object->add_observer( \&catch_observation );

	 # Define the observable class as a parent and allow the observers to
	 # be used by the child

	 package My::Parent;

	 use strict;
	 use base qw( Class::Observable );

	 sub prepare_for_bed {
	     my ( $self ) = @_;
	     $self->notify_observers( 'prepare_for_bed' );
	 }

	 sub brush_teeth {
	     my ( $self ) = @_;
	     $self->_brush_teeth( time => 45 );
	     $self->_floss_teeth( time => 30 );
	     $self->_gargle( time => 30 );
	 }

	 sub wash_face { ... }

	 package My::Child;

	 use strict;
	 use base qw( My::Parent );

	 sub brush_teeth {
	     my ( $self ) = @_;
	     $self->_wet_toothbrush();
	 }

	 sub wash_face { return }

	 # Create a class-based observer

	 package My::ParentRules;

	 sub update {
	     my ( $item, $action ) = @_;
	     if ( $action eq 'prepare_for_bed' ) {
		 $item->brush_teeth;
		 $item->wash_face;
	     }
	 }

	 My::Parent->add_observer( __PACKAGE__ );

	 $parent->prepare_for_bed # brush, floss, gargle, and wash face
	 $child->prepare_for_bed  # pretend to brush, pretend to wash face

DESCRIPTION
       If you have ever used Java, you may have run across the
       "java.util.Observable" class and the "java.util.Observer" interface.
       With them you can decouple an object from the one or more objects that
       wish to be notified whenever particular events occur.

       These events occur based on a contract with the observed item. They may
       occur at the beginning, in the middle or end of a method. In addition,
       the object knows that it is being observed. It just does not know how
       many or what types of objects are doing the observing. It can therefore
       control when the messages get sent to the obsevers.

       The behavior of the observers is up to you. However, be aware that we
       do not do any error handling from calls to the observers. If an
       observer throws a "die", it will bubble up to the observed item and
       require handling there. So be careful.

       Throughout this documentation we refer to an 'observed item' or
       'observable item'. This ambiguity refers to the fact that both a class
       and an object can be observed. The behavior when notifying observers is
       identical. The only difference comes in which observers are notified.
       (See "Observable Classes and Objects" for more information.)

   Observable Classes and Objects
       The observable item does not need to implement any extra methods or
       variables. Whenever it wants to let observers know about a state-change
       or occurrence in the object, it just needs to call
       "notify_observers()".

       As noted above, whether the observed item is a class or object does not
       matter -- the behavior is the same. The difference comes in determining
       which observers are to be notified:

       ·   If the observed item is a class, all objects instantiated from that
	   class will use these observers. In addition, all subclasses and
	   objects instantiated from the subclasses will use these observers.

       ·   If the observed item is an object, only that particular object will
	   use its observers. Once it falls out of scope then the observers
	   will no longer be available. (See "Observable Objects and DESTROY"
	   below.)

       Whichever you chose, your documentation should make clear which type of
       observed item observers can expect.

       So given the following example:

	BEGIN {
	    package Foo;
	    use base qw( Class::Observable );
	    sub new { return bless( {}, $_[0] ) }
	    sub yodel { $_[0]->notify_observers }

	    package Baz;
	    use base qw( Foo );
	    sub yell { $_[0]->notify_observers }
	}

	sub observer_a { print "Observation A from [$_[0]]\n" }
	sub observer_b { print "Observation B from [$_[0]]\n" }
	sub observer_c { print "Observation C from [$_[0]]\n" }

	Foo->add_observer( \&observer_a );
	Baz->add_observer( \&observer_b );

	my $foo = Foo->new;
	print "Yodeling...\n";
	$foo->yodel;

	my $baz_a = Baz->new;
	print "Yelling A...\n";
	$baz_a->yell;

	my $baz_b = Baz->new;
	$baz_b->add_observer( \&observer_c );
	print "Yelling B...\n";
	$baz_b->yell;

       You would see something like

	Yodeling...
	Observation A from [Foo=HASH(0x80f7acc)]
	Yelling A...
	Observation B from [Baz=HASH(0x815c2b4)]
	Observation A from [Baz=HASH(0x815c2b4)]
	Yelling B...
	Observation C from [Baz=HASH(0x815c344)]
	Observation B from [Baz=HASH(0x815c344)]
	Observation A from [Baz=HASH(0x815c344)]

       And since "Bar" is a child of "Foo" and each has one class-level
       observer, running either:

	my @observers = Baz->get_observers();
	my @observers = $baz_a->get_observers();

       would return a two-item list. The first item would be the "observer_b"
       code reference, the second the "observer_a" code reference. Running:

	my @observers = $baz_b->get_observers();

       would return a three-item list, including the observer for that
       specific object ("observer_c" coderef) as well as from its class (Baz)
       and the parent (Foo) of its class.

   Observers
       There are three types of observers: classes, objects, and subroutines.
       All three respond to events when "notify_observers()" is called from an
       observable item. The differences among the three are are:

       ·   A class or object observer must implement a method "update()" which
	   is called when a state-change occurs. The name of the subroutine
	   observer is irrelevant.

       ·   A class or object observer must take at least two arguments: itself
	   and the observed item. The subroutine observer is obligated to take
	   only one argument, the observed item.

	   Both types of observers may also take an action name and a hashref
	   of parameters as optional arguments. Whether these are used depends
	   on the observed item.

       ·   Object observers can maintain state between responding to
	   observations.

       Examples:

       Subroutine observer:

	sub respond {
	    my ( $item, $action, $params ) = @_;
	    return unless ( $action eq 'update' );
	    # ...
	}
	$observable->add_observer( \&respond );

       Class observer:

	package My::ObserverC;

	sub update {
	    my ( $class, $item, $action, $params ) = @_;
	    return unless ( $action eq 'update' );
	    # ...
	}

       Object observer:

	package My::ObserverO;

	sub new {
	    my ( $class, $type ) = @_;
	    return bless ( { type => $type }, $class );
	}

	sub update {
	    my ( $self, $item, $action, $params ) = @_;
	    return unless ( $action eq $self->{type} );
	    # ...
	}

   Observable Objects and DESTROY
       Previous versions of this module had a problem with maintaining
       references to observable objects/coderefs. As a result they'd never be
       destroyed. As of 1.04 we're using weak references with "weaken" in
       Scalar::Util so this shouldn't be a problem any longer.

METHODS
   Observed Item Methods
       notify_observers( [ $action, @params ] )

       Called from the observed item, this method sends a message to all
       observers that a state-change has occurred. The observed item can
       optionally include additional information about the type of change that
       has occurred and any additional parameters @params which get passed
       along to each observer. The observed item should indicate in its API
       what information will be passed along to the observers in $action and
       @params.

       Returns: Nothing

       Example:

	sub remove {
	    my ( $self ) = @_;
	    eval { $self->_remove_item_from_datastore };
	    if ( $@ ) {
		$self->notify_observers( 'remove-fail', error_message => $@ );
	    }
	    else {
		$self->notify_observers( 'remove' );
	    }
	}

       add_observer( @observers )

       Adds the one or more observers (@observer) to the observed item. Each
       observer can be a class name, object or subroutine -- see "Types of
       Observers".

       Returns: The number of observers now observing the item.

       Example:

	# Add a salary check (as a subroutine observer) for a particular
	# person
	my $person = Person->fetch( 3843857 );
	$person->add_observer( \&salary_check );

	# Add a salary check (as a class observer) for all people
	Person->add_observer( 'Validate::Salary' );

	# Add a salary check (as an object observer) for all people
	my $salary_policy = Company::Policy::Salary->new( 'pretax' );
	Person->add_observer( $salary_policy );

       delete_observer( @observers )

       Removes the one or more observers (@observer) from the observed item.
       Each observer can be a class name, object or subroutine -- see "Types
       of Observers".

       Note that this only deletes each observer from the observed item
       itself. It does not remove observer from any parent classes. Therefore,
       if an observer is not registered directly with the observed item
       nothing will be removed.

       Returns: The number of observers now observing the item.

       Examples:

	# Remove a class observer from an object
	$person->delete_observer( 'Lech::Ogler' );

	# Remove an object observer from a class
	Person->delete_observer( $salary_policy );

       delete_all_observers()

       Removes all observers from the observed item.

       Note that this only deletes observers registered directly with the
       observed item. It does not clear out observers from any parent classes.

       WARNING: This method was renamed from "delete_observers". The
       "delete_observers" call still works but is deprecated and will
       eventually be removed.

       Returns: The number of observers removed.

       Example:

	Person->delete_all_observers();

       get_observers()

       Returns all observers for an observed item, as well as the observers
       for its class and parents as applicable. See "Observable Classes and
       Objects" for more information.

       Returns: list of observers.

       Example:

	my @observers = Person->get_observers;
	foreach my $o ( @observers ) {
	    print "Observer is a: ";
	    print "Class"      unless ( ref $o );
	    print "Subroutine" if ( ref $o eq 'CODE' );
	    print "Object"     if ( ref $o and ref $o ne 'CODE' );
	    print "\n";
	}

       copy_observers( $copy_to_observable )

       Copies all observers from one observed item to another. We get all
       observers from the source, including the observers of parents. (Behind
       the scenes we just use "get_observers()", so read that for what we
       copy.)

       We make no effort to ensure we don't copy an observer that's already
       watching the object we're copying to. If this happens you will appear
       to get duplicate observations. (But it shouldn't happen often, if
       ever.)

       Returns: number of observers copied

       Example:

	# Copy all observers of the 'Person' class to also observe the
	# 'Address' class

	Person->copy_observers( Address );

	# Copy all observers of a $person to also observe a particular
	# $address

	$person->copy_observers( $address )

       count_observers()

       Counts the number of observers for an observed item, including ones
       inherited from its class and/or parent classes. See "Observable Classes
       and Objects" for more information.

   Debugging Methods
       Note that the debugging messages will try to get information about the
       observed item if called from an object. If you have an "id()" method in
       the object its value will be used in the message, otherwise it will be
       described as "an instance of class Foo".

       SET_DEBUG( $bool )

       Turn debugging on or off. If set the built-in implementation of
       "observer_log()" will issue a warn at appropriate times during the
       process.

       observer_log( @message )

       Issues a "warn" if "SET_DEBUG" hsa been called with a true value. This
       gets called multiple times during the registration and notification
       process.

       To catch the "warn" calls just override this method.

       observer_error( @message )

       Issues a "die" if we catch an exception when notifying observers. To
       catch the "die" and do something else with it just override this
       method.

RESOURCES
       APIs for "java.util.Observable" and "java.util.Observer". (Docs below
       are included with JDK 1.4 but have been consistent for some time.)

       <http://java.sun.com/j2se/1.4/docs/api/java/util/Observable.html>

       <http://java.sun.com/j2se/1.4/docs/api/java/util/Observer.html>

       "Observer and Observable", Todd Sundsted,
       http://www.javaworld.com/javaworld/jw-10-1996/jw-10-howto_p.html
       <http://www.javaworld.com/javaworld/jw-10-1996/jw-10-howto_p.html>

       "Java Tip 29: How to decouple the Observer/Observable object model",
       Albert Lopez, http://www.javaworld.com/javatips/jw-javatip29_p.html
       <http://www.javaworld.com/javatips/jw-javatip29_p.html>

SEE ALSO
       Class::ISA

       Class::Trigger

       Aspect

COPYRIGHT
       Copyright (c) 2002-2004 Chris Winters. All rights reserved.

       This library is free software; you can redistribute it and/or modify it
       under the same terms as Perl itself.

AUTHOR
       Chris Winters <chris@cwinters.com>

perl v5.14.0			  2004-10-16		  Class::Observable(3)
[top]

List of man pages available for Pidora

Copyright (c) for man pages and the logo by the respective OS vendor.

For those who want to learn more, the polarhome community provides shell access and support.

[legal] [privacy] [GNU] [policy] [cookies] [netiquette] [sponsors] [FAQ]
Tweet
Polarhome, production since 1999.
Member of Polarhome portal.
Based on Fawad Halim's script.
....................................................................
Vote for polarhome
Free Shell Accounts :: the biggest list on the net