Introduction to the Harvester Design Pattern

This article is about the Harvester Pattern. It is not an official design pattern, at least not one I found anything about online but since it's used a lot in Ivy I decided to write something about it.

It's all about who's in control

The harvester pattern allows a type of loose coupling between objects, providing a simple scalable solution to a variety of different problems you can encounter.

The main advantage is that the harvester object (the main object) stays in control and the subject classes don't have to be aware of the main object.

Here's how a typical setup for a eventhandler would be and as you can see the objects of the EventHandler type register their own events with the EventManager and have to be made aware of the EventManager.

*
 * Simple event class to demonstrate a non-harvester approach
 * @author Rob Theeuwes - ThiOz.com
 */
class TypicalEventManager
{
   
    private $_aHandlers = array();
   
    function registerHandler($sEvent, $oHandler, $sCallback)
    {
       
        $this->_aHandlers[$sEvent][] = array('object' => $oHandler, 'callback'=> $sCallback);
    }
   
    public function fireEvent($sEvent)
    {
        if(isset($this->_aHandlers[$sEvent]))
        {
                $aHandlers = $this->_aHandlers[$sEvent];
                foreach($aHandlers as $aHandler)
                {
                    $oEventObject = $aHandler['object'];
                    call_user_func_array( array($oEventObject, $aHandler['callback']), array() );
                }
        }       
    }   
}

class EventHandler
{
    protected $_aEvents = array();
    protected $_oManager;
   
    function __construct($oManager)
    {
        $this->_oManager = $oManager;
        $this->_registerHandlers();
    }
   
    function _registerHandlers()
    {
        foreach($this->_aEvents as $sEvent => $sCallback)
        {
            $this->_oManager->registerHandler($sEvent, $this, $sCallback);
        }
    }
   
   
}

class MailEventHandler extends EventHandler
{
    protected $_aEvents = array('mail_sent' => 'onMailSent');

    function onMailSent()
    {
        echo 'mail sent';
    }
}

class PrintEventHandler extends EventHandler
{
    protected $_aEvents = array('message_print' => 'onMessagePrint');
   
    function onMessagePrint()
    {
        echo 'message printed';
    }
}

$oManager = new TypicalEventManager();
$oPrintEventHandler = new PrintEventHandler($oManager);
$oMailEventHandler = new MailEventHandler($oManager);

$oManager->fireEvent('mail_sent');

 Let's look at what's different with the harvester pattern applied.