在传统的面向过程语言中经常充斥着大量的 if/else 语句。这种情况不仅容易令逻辑变得混乱,而且修改麻烦。strategy 策略模式正是为了解决此类问题而诞生的。
当我们遇到一个问题,有多种解决的策略时,我们就可以用 strategy 模式。它的主要思想就是为所有策略类 subclasses 提供一个统一的固定的接口 interface ,例如一个父类 parent 。我们可以用这个接口定义各种所需的策略。
下面让我们看看 Zend_Application_Resource_Resource 是如何实现 strategy 的。
以下都是经过简化的源代码,首先是统一接口 :
/**
* bootstrap resources 资源统一接口
*/
interface Zend_Application_Resource_Resource
{
// Constructor 初始化函数
public function __construct($options = null);
// 其它函数
public function setBootstrap(Zend_Application_Bootstrap_Bootstrapper $bootstrap);
public function getBootstrap();
public function setOptions(array $options);
public function getOptions();
/**
* Strategy 模式 : 统一的 init 方法
* @return mixed
*/
public function init();
}
接着是父类 Zend_Application_Resource_ResourceAbstract :
/**
* @see Zend_Application_Resource_Resource
*/
require_once 'Zend/Application/Resource/Resource.php';
/**
* 资源虚拟父类
* @uses Zend_Application_Resource_Resource
*/
abstract class Zend_Application_Resource_ResourceAbstract implementsZend_Application_Resource_Resource
{
// 实现接口函数
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()方法将在子类中实现
}
注意我们没有在父类中实现 init() 方法,而且因为父类被声明为 abstract 的关系,我们必须在其子类中实现 init() 函数,才可以正常使用 resource 资源。以下是 Layout 及 View 两个例子。
Zend_Application_Resource_Layout :
/**
* 配置 layout 资源类 : Zend_Application_Resource_Layout
* @uses Zend_Application_Resource_ResourceAbstract
*/
class Zend_Application_Resource_Layout
extends Zend_Application_Resource_ResourceAbstract
{
// @var Zend_Layout
protected $_layout;
/**
* 由 Zend_Application_Resource_Resource 定义
* @return Zend_Layout
*/
public function init()
{
$this->getBootstrap()->bootstrap('FrontController');
return $this->getLayout();
}
/**
* 获取 layout 对象
* @return Zend_Layout
*/
public function getLayout()
{
if (null === $this->_layout) {
$this->_layout = Zend_Layout::startMvc($this->getOptions());
}
return $this->_layout;
}
}
Zend_Application_Resource_View :
/**
* 配置 view 资源类 : 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;
/**
* 由 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;
}
/**
* 获取 view 对象
* @return Zend_View
*/
public function getView()
{
if (null === $this->_view) {
$this->_view = new Zend_View($this->getOptions());
}
return $this->_view;
}
}
而真正调用 init() 的则是 Zend_Application_Bootstrap_Bootstrap 类。它负责收集所有资源并执行其初始化函数 init() :
/**
* Zend_Application_Bootstrap_Bootstrap::_executeResource($resource)
* 调用一个资源
*/
protected function _executeResource($resource)
{
// ......
if ($this->hasPluginResource($resource)) {
// ......
$plugin = $this->getPluginResource($resource);
$return = $plugin->init();
// ......
}
}
这就是 Zend_Application_Bootstrap_Bootstrap 引用资源并初始化资源的解决方案。同时,我们还可以通过其通用接口 Zend_Application_Resource_ResourceAbstract ,很方便的实现自己的资源。
实际上 Zend Framework 大量使用了 strategy 策略模式,在 Zend_Controller_Action_Helper,Zend_View_Helper,Zend_Filter 等等中都可以见到它的身影。
转自:http://kbs.kimbs.cn/blog/list/post/15/title/strategy-pattern-in-Zend-Framework