Strategy Pattern in Zend Framework

In the traditional process-oriented languages are often filled with a lot of if/else statements. This situation has easily made the logic of chaos and trouble to amend. The strategy design pattern was borned to solve this kind of problems.

 

When we face a problem which got serveral solution strategies, we can use the strategy pattern. Its main idea is to provide a unified and fixed interface for all strategy subclasses, for example, a parent class. And then we just use this interface to define each strategy we want.

 

Now let’s take a look at how Zend_Application_Resource_Resource implements the strategy pattern.

 

 

The following are simplified source code and first of all, is a unified interface : 

 

<?php
/**
 * bootstrap resources : unified interface
 */

interface Zend_Application_Resource_Resource
{
    // Constructor
    public function __construct($options = null);

    // Other functions
    public function setBootstrap(Zend_Application_Bootstrap_Bootstrapper $bootstrap);
    public function getBootstrap();
    public function setOptions(array $options);
    public function getOptions();

    /**
     * Strategy pattern : init() method
     * @return mixed
     */

    public function init();
}

 

Then the parent Zend_Application_Resource_ResourceAbstract

 

<?php
/**
 * @see Zend_Application_Resource_Resource
 */

require_once 'Zend/Application/Resource/Resource.php';

/**
 * Parent : Resource
 * @uses Zend_Application_Resource_Resource
 */

abstract class Zend_Application_Resource_ResourceAbstract implements Zend_Application_Resource_Resource
{
    // Implements interface methods
    public function __construct($options = null)
    {
        // ......
    }

    public function setOptions(array $options)
    {
        //......
        return $this;
    }

    public function getOptions()
    {
        // ......
    }

    public function setBootstrap(Zend_Application_Bootstrap_Bootstrapper $bootstrap)
    {
        // ......
        return $this;
    }

    public function getBootstrap()
    {
        // ......
    }

    // ......

    // init() is left for subclasses to implement
}

 

We haven’t implemented the init() function within parent, but also because the parent is defined as abstract, we can only to subclass for the realization of its init() function. In this case we can make the use of resources properly. Here are two examples about the Layout and the View.

 

Zend_Application_Resource_Layout :

 

<?php
/**
 * Layout resource : Zend_Application_Resource_Layout
 * @uses Zend_Application_Resource_ResourceAbstract
 */

class Zend_Application_Resource_Layout
    extends Zend_Application_Resource_ResourceAbstract
{
    // @var Zend_Layout
    protected $_layout;

    /**
     * Defined in Zend_Application_Resource_Resource
     * @return Zend_Layout
     */

    public function init()
    {
        $this->getBootstrap()->bootstrap('FrontController');
        return $this->getLayout();
    }

    /**
     * Get the layout object
     * @return Zend_Layout
     */

    public function getLayout()
    {
        if (null === $this->_layout) {
            $this->_layout = Zend_Layout::startMvc($this->getOptions());
        }
        return $this->_layout;
    }
}

 

Zend_Application_Resource_View : 

 

<?php
/**
 * View resource : Zend_Application_Resource_View
 * @uses Zend_Application_Resource_ResourceAbstract
 */

class Zend_Application_Resource_View
    extends Zend_Application_Resource_ResourceAbstract
    {
    // @var Zend_View_Interface
    protected $_view;

    /**
     * Defined in Zend_Application_Resource_Resource
     * @return Zend_View
     */

    public function init()
    {
        $view = $this->getView();
        $viewRenderer = new Zend_Controller_Action_Helper_ViewRenderer();
        $viewRenderer->setView($view);
        Zend_Controller_Action_HelperBroker::addHelper($viewRenderer);
        return $view;
    }

    /**
     * Get the view object
     * @return Zend_View
     */

    public function getView()
    {
        if (null === $this->_view) {
            $this->_view = new Zend_View($this->getOptions());
        }
        return $this->_view;
    }
}

 

It’s Zend_Application_Bootstrap_Bootstrap who make the really call of init(). It is responsible to collect all the resources and the implementation of their initialization function init() : 

 

<?php
/**
 * Zend_Application_Bootstrap_Bootstrap::_executeResource($resource)
 * Execute one resource
 */

protected function _executeResource($resource)
{
    // ......

    if ($this->hasPluginResource($resource)) {
        // ......
        $plugin = $this->getPluginResource($resource);
        $return = $plugin->init();
        // ......
    }
}

 

This is how Zend_Application_Bootstrap_Bootstrap use resouces and the solution of resources initialization. At the same time, we can create our own resouces very easily through the common interface provided by Zend_Application_Resource_ResourceAbstract.

 

In fact, large-scale use of strategy pattern has been found in Zend Framework including : Zend_Controller_Action_Helper, Zend_View_Helper, Zend_Filter etc.

 

Posted in Design Patterns | Tagged , | Leave a comment