Editors Note, February 14th 2022: This project is now ABANDONED and no longer supported or updated.

asherwunk/phabstractic now supports the Observer and Publisher design patterns.

Observer/Publisher Design Pattern

Observer and Publisher software design patterns are useful and are used in tandem to implement such things as event-oriented programming.  These are actually two design patterns that work can work together, and because of that only one side is usually documented, that being the observer pattern.  I consider them two different patterns because you do two different things (observer or publish).  Here is a quote from Wikipedia on the observer design pattern:

The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

Because I consider them two different things, I implemented them as two different patterns in phabstractic.  This gave rise to the fact that both an observer and a publisher register the connections between objects.  I will explain this further when I write about the interaction between the two patterns.  First, let’s examine the Observer patterns implemented in PHP with Phabstractic.

Observer Design Pattern

When I think of an observer, I think of an object that has a need to be notified of something.  When I think about this notification I rely on the idea of finite-state machines, which are an entirely different subject, but the idea is that different states are entered at any one time.  Any ‘event’, such as a mouse-click or a list insertion can be identified as something changing the state that it’s in.  So, any time an observer is notified of something, that ‘state’ is portrayed as a message.

In order to separate or discern something like a message, in particular, I decided I would make any piece of data distinguishable as indicating ‘state’.  In this line of thought, I developed an interface to define something that contained ‘state’, so that any object can implement this interface and act as an indicator of state (view on github):

namespace Phabstractic\Patterns\Resource
{
    interface StateInterface
    {
        public function getState();
        
        public function setState($stateData);

    }   
}

This is all well and good.  I wanted to make sure any object could be identified as an observer, so I first outlined what my observer would do in an interface file (view on github):

namespace Phabstractic\Patterns\Resource
{
    interface ObserverInterface
    {
        public function notifyObserver(
            PublisherInterface &$publisher,
            StateInterface &$state
        );
        
        public function attachPublisher(PublisherInterface $publisher);
        
        public function detachPublisher(PublisherInterface $publisher);
        
        public function unlinkFromPublishers();
        
        public function getPublishers();
           
    }   
}

The idea here is that an observer will register ‘publishers’, or objects that are granted the ability to notify the observer object, which will, upon state change, call the observers’ notifyObserver()  method.  The maintaining of a list of publishers is optional, as any object can notify the observer simply by executing a call to the public notifyObserver()  method.  However, I decided that if I was implementing the observer as separate from the publisher I would make sure we would provide a method or way that we could see who or what the observer object is listening to.

Here, I implement the observer pattern as a PHP trait.  Because PHP is a single inheritance language, that is a class can inherit from only one other class, it wouldn’t make a lot of sense to make observer functionality as a parent class.  Any object could be an observer, so the parent relationship of an object/class may already be taken up.  Introducing the observer pattern as another step in the inheritance chain isn’t feasible when disparate pieces of code can be observers.  Here is the trait (view on github):

namespace Phabstractic\Patterns
{
    use Phabstractic\Data\Types\Type;
    use Phabstractic\Data\Types;
    use Phabstractic\Patterns\Resource as PatternsResource;
    use Phabstractic\Features;
    
    trait ObserverTrait
    {
        protected $observedSubjects = null;
        
        protected function constructObservedSubjects() {
            if ($this->observedSubjects == null) {
                $this->observedSubjects = new Types\RestrictedSet(
                    array(),
                    new Types\Restrictions(
                        array(Type::BASIC_NULL, Type::TYPED_OBJECT),
                        array('Phabstractic\\Patterns\\Resource\\PublisherInterface'),
                        array('strict' => true)
                    ),
                    array( 'strict' => true )
                );
            }
        }
        
        public function detachPublisher(PatternsResource\PublisherInterface $publisher)
        {
            $this->constructObservedSubjects();
            
            if ($this->observedSubjects->in($publisher)) {
                $this->observedSubjects->remove($publisher);
                $publisher->detachObserver($this);
            }
        }
        
        public function attachPublisher(PatternsResource\PublisherInterface $publisher)
        {
            $this->constructObservedSubjects();
            
            if (!$this->observedSubjects->in($publisher)) {
                $this->observedSubjects->add($publisher);
                $publisher->attachObserver($this);
            }
        }
        
        public function unlinkFromPublishers()
        {
            $this->constructObservedSubjects();
            
            Types\RestrictedSet::mapInternal(
                'detachListener',
                array($this),
                $this->observedSubjects
            );
            
            $this->observedSubjects->clear();
        }
        
        public function getPublishers()
        {
            $this->constructObservedSubjects();
            
            return $this->observedSubjects->getPlainArray();
        }
     
        public function notifyObserver(
            PatternsResource\PublisherInterface &$publisher,
            PatternsResource\StateInterface &$state
        ) {
            // default behavior
            if (is_string($state->getState())) {
                $method = 'published' . ucfirst($state->getState());
            
                // looks for an observer method with the state name
                if (method_exists($this, $method)) {
                    call_user_func_array(
                        array($this, $method),
                        array($publisher, $state)
                    );
                    
                    return true;
                }
                
            }
            
            return false;
        }
        
    }    
}

As you can see, I couple this implementation of the observer design pattern with my implementation of the publisher design pattern.  We’ll cover the publisher design pattern below.

The default behavior of notifyObserver()  is to call a method on the observing object prefixed with ‘published’.  So if I passed a state object with the data ‘done’ to the default notifyObserver() it would search and call the method named ‘publishedYellow()‘ on its host object.

Publisher Design Pattern

A publisher is an object that maintains a list of observer objects whom it notifies when there is a ‘state change’.  Much like the observer, I wanted to be able to distinguish objects as being publishers, and a good way of doing that is type-ducking or using interfaces (view on github):

namespace Phabstractic\Patterns\Resource
{
    interface PublisherInterface
    {
        public function attachObserver(ObserverInterface $observer);
        
        public function detachObserver(ObserverInterface $observer);
        
        public function unlinkFromObservers();
        
        public function getObservers();
        
        public function announce();
        
        public function getStateObject();
        
        public function setStateObject(StateInterface $state);

    }   
}

Here you can see the methods for attaching and detaching observers to the object.  You’ll also see methods for manipulating and storing a ‘state’ object as outlined above in the StateInterface.

I also implemented the publisher design pattern as a trait for the same reasons I did the observer design pattern.  I want any object, regardless of its position in an inheritance hierarchy to be able to be an observer or a publisher (view on github):

namespace Phabstractic\Patterns
{
    use Phabstractic\Data\Types\Type;
    use Phabstractic\Data\Types;
    use Phabstractic\Patterns\Resource as PatternsResource;
    
    trait PublisherTrait
    {
        protected $publisherObservers = null;
        
        protected $publisherState = null;
        
        protected function constructPublisherObservers() {
            if ($this->publisherObservers == null) {
                $this->publisherObservers = new Types\RestrictedSet(
                    array(),
                    new Types\Restrictions(
                        array(Type::BASIC_NULL, Type::TYPED_OBJECT),
                        array('Phabstractic\\Patterns\\Resource\\ObserverInterface'),
                        array('strict' => true)
                    ),
                    array( 'strict' => true )
                );
            }
        }
     
        public function attachObserver(PatternsResource\ObserverInterface $observer)
        {
            $this->constructPublisherObservers();
            
            if (!$this->publisherObservers->in($observer)) {
                $this->publisherObservers->add($observer);
                $observer->attachPublisher($this);
            }
        }
     
        public function detachObserver(PatternsResource\ObserverInterface $observer)
        {
            $this->constructPublisherObservers();
            
            if ($this->publisherObservers->in($observer)) {
                $this->publisherObservers->remove($observer);
                $observer->detachPublisher($this);
            }
        }
        
        public function unlinkFromObservers()
        {
            $this->constructPublisherObservers();
            
            Types\RestrictedSet::mapInternal(
                'detach',
                array($this),
                $this->publisherObservers
            );
            
            $this->publisherObservers->clear();
        }
     
        public function getObservers()
        {
            $this->constructPublisherObservers();
            
            return $this->publisherObservers->getPlainArray();
        }
     
        public function setStateObject(PatternsResource\StateInterface $state)
        {
            $this->publisherState = $state;
            $this->announce();
        }
        
        public function getStateObject()
        {
            return $this->publisherState;
        }
     
        public function announce()
        {
            $this->constructPublisherObservers();
            
            Types\RestrictedSet::mapInternal(
                'notifyObserver',
                array(&$this, &$this->publisherState),
                $this->publisherObservers
            );
            
        }       
    }
}

In the previous implementation, the maintained list of objects wasn’t necessary to the operation of the object.  Any outside object or function could call the observer’s notifyObserver() method to notify the observer of any state change anywhere.  This is not the case for a publisher.  When the publisher object’s state changes, it cycles through the maintained list of observers and then calls that observer’s notify method.

Working Together

The nice thing about implementing the observer and publisher independently, but also together is that we can determine how they work together.  By insisting that interfaces are followed before connecting and disconnecting from each other we can maintain the list of objects in both the observer and the publisher at once.

You’ll note how in attachObserver() we and attachPublisher() we do the same bit of logic:

if (!$this->observedSubjects->in($publisher)) {
    $this->observedSubjects->add($publisher);
    $publisher->attachObserver($this);
}

So when we attach a publisher to an observer, it automatically keeps track of it in its own records, and when we attach an observer to a publisher it automatically keeps track of it in its own records.

You’ll notice the list of maintained objects is a Restricted Set.  I covered Phabstractic’s implementation of Restricted Sets in a previous post.

Conclusion

Observers and Publisher design patterns are very important in that they enable a certain amount of reactive programming.  When you only want something to execute or occur when a particular event occurs it makes more sense to just test for state change than to hard code in an if clause for every step.  This way you can structure the execution pathway in an object-oriented fashion.  This allows for more agent-oriented programming, as well as opens doors to such methods as parallel processing or graphical user interface programming.

This is part of the Phabstractic Library.

photo credit: Color Me Rad 2016 via photopin (license)

Asher Wolfstein

Metaverse Resident

About the Author

A metaverse resident, you can find me on Second Life (kadar.talbot) and other online platforms. I write about my digital life, my musings, and my projects as a programmer, webmaster, artist, and game designer. (exist (be wunk) (use rational imagination) (import artist coder maker furry) (conditional (if (eq you asshole) (me (block you))))

View Articles