天天看點

Zend Framework 與設計模式 (二) - registry 注冊者模式

注冊者模式 (registry) 提供了一種機制,能讓你在程式中有條理的存放并管理對象 (object) ,它的主要作用是防止使用者濫用全局對象 (global object) 。

Registry 通常提供對象的存取,登出等方法,友善使用者管理。下面來看看 Zend Framework 中 registry 的例子,這裡挑選最經典的 Zend_Registry 為例 :

class Zend_Registry extends ArrayObject
{
    ......

    // Registry 私有對象是用來存儲共享對象的注冊者
    private static $_registry = null;

    // Constructor 初始化為 ArrayObject 對象
    // @link http://www.php.net/manual/en/class.arrayobject.php
    public function __construct($array = array(), $flags = parent::ARRAY_AS_PROPS)
    {
        parent::__construct($array, $flags);
    }

    // 傳回預設的注冊對象執行個體
    public static function getInstance()
    {
        if (self::$_registry === null) {
            self::$_registry = new Zend_Registry();
        }

        return self::$_registry;
    }

    // 銷毀注冊者
    public static function _unsetInstance()
    {
        self::$_registry = null;
    }

    // Getter 方法,基于 ArrayObject 的 offsetGet() 方法,提取存儲的執行個體。
    public static function get($index)
    {
        $instance = self::getInstance();
        ...
        return $instance->offsetGet($index);
    }

    // Setter 方法,基于 ArrayObject 的 offsetSet() 方法,存儲執行個體。
    public static function set($index, $value)
    {
        $instance = self::getInstance();
        $instance->offsetSet($index, $value);
    }

    ......
}      

上面是經過簡化而得的源代碼,值得注意的是 Zend_Registry 繼承自 ArrayObject ,也就是說 Zend_Registry 完全能以數組的形式來進行操作。

以下的用法在本質上是一樣的 :

Zend_Registry::set($name, $value);
......
$value2 = Zend_Registry::get($name);


$registry= Zend_Registry::getInstance();
$registry[$name] = $value;
......
$value2 = $registry[$name];      

另外 registry 通常可以與單元子模式 singleton 搭配使用 (singleton - 參見 "​Zend Framework 與設計模式(一) - singleton 單元子模式​"一章),例如 :

class singletonExample
{
    ...

    // Singleton 單元子對象
    public static function getInstance()
    {
        if (false == Zend_Registry::isRegistered('singletonExample')) {
            Zend_Registry::set('singletonExample', new self());
        }

        return Zend_Registry::get('singletonExample');
    }

    ...
}      

在 Zend_Framework 中,Zend_Registry 還扮演了架構建構者的角色。例如在 Zend_View_Helper_Translate 中,Zend_Registry 為翻譯器 (translate) 視圖助手提供了預設的翻譯者 (translator) :

class Zend_View_Helper_Translate extends Zend_View_Helper_Abstract
{
    ...

    // 擷取翻譯對象
    // 如果目前沒有設定翻譯者,則嘗試從注冊者中根據關鍵詞 Zend_Translate 來尋找
    public function getTranslator()
    {
        if ($this->_translator === null) {
            require_once 'Zend/Registry.php';
            if (Zend_Registry::isRegistered('Zend_Translate') === true) {
                $this->setTranslator(Zend_Registry::get('Zend_Translate'));
            }
        }

        return $this->_translator;
    }

    ...
}