将注册模式实现为单件模式:
如前所述,把注册模式实现为单件模式有很多实现方式。
第一步,将注册模式实现为单件对象,(作者注:我们在第四章——The Singleton Pattern末尾简单讨论过)。
按照这种设计,注册模式类的任何一个实例都将访问同一个数组。我们把这个新类叫做RegistryGlobal以区别于我们前面开发的类,并反映这种实现方式的特性。
以下为反映这种思想的测试用例(它应该看起来很熟悉)。
代码:
class RegistryGlobalPHP4TestCase extends UnitTestCase { function testRegistryGlobal() { $reg =& new RegistryGlobal; $this->assertFalse($reg->isValid('key')); $this->assertNull($reg->get('key')); $test_value = 'something'; $reg->set('key', $test_value); $this->assertReference($test_value, $reg->get('key')); } }
实现代码如下所示:
class RegistryGlobal { var $_store = array(); function isValid($key) { return array_key_exists($key, $this->_store); } function &get($key) { if (array_key_exists($key, $this->_store)) return $this->_store[$key]; } function set($key, &$obj) { $this->_store[$key] =& $obj; } }
isValid(), get(),和set()方法与我们前面开发的注册模式类完全相同。
下一步:我们来编写验证RegistryGlobal类是单件模式的测试用例。
代码:
class RegistryGlobalPHP4TestCase extends UnitTestCase { function testRegistryGlobal() { /*...*/ } function testRegistryGlobalIsMonoState() { $reg =& new RegistryGlobal; $reg2 =& new RegistryGlobal; $this->assertCopy($reg, $reg2); $test_value = 'something'; $reg->set('test', $test_value); $this->assertReference( $reg->get('test') ,$reg2->get('test')); } }
这里测试用例创建了RegistryGlobal类的两个实例,并确认他们不是对同一对象的引用——在一个实例内设置一个对象的属性值(value),最后证实两个实例返回相同的对象。若测试通过RegistryGlobal类就拥有单态的行为。
代码:
define('REGISTRY_GLOBAL_STORE', '__registry_global_store_key__'); class RegistryGlobal {var $_store; function RegistryGlobal() {if (!array_key_exists(REGISTRY_GLOBAL_STORE, $GLOBALS)||!is_array($GLOBALS[REGISTRY_GLOBAL_STORE])) {$GLOBALS[REGISTRY_GLOBAL_STORE] = array(); } $this->_store =& $GLOBALS[REGISTRY_GLOBAL_STORE]; } function isValid($key) {return array_key_exists($key, $this->_store);} function &get($key) {if (array_key_exists($key, $this->_store)) return $this->_store[$key];} function set($key, &$obj) { $this->_store[$key] =& $obj; } }
本方法中的神奇之处在于$this->_store =& $GLOBALS[REGISTRY_GLOBAL_STORE;] 这一行,引用操作符将全局数组绑定到实例变量$_store上。这是单件模式实现的关键所在:每次在对象中使用$this->_store变量时,作用反映到全局变量中。
但是并不推荐基于全局变量的解决方案。如果PHP4支持这一特性的话,静态类变量会是更好的解决方案。然而,我们可以在代码中通过引用实现静态类变量吗?
测试与 RegistryGlobal 类的测试相似。
代码:
class RegistryMonoStatePHP4TestCase extends UnitTestCase { function testRegistryMonoState() { $this->assertCopy( $reg =& new RegistryMonoState; $reg2 =& new RegistryMonoState); $this->assertFalse($reg->isValid(‘key’)); $this->assertNull($reg->get(‘key’)); $test_value = ‘something’; $reg->set(‘key’, $test_value); $this->assertReference($reg->get(‘key’), $reg2->get(‘key’)); } }
要自己实现类静态变量,可以将一个对函数静态变量的引用绑定到类的实例变量上。
代码:
class RegistryMonoState {var $_store; function &_initRegistry() { static $store = array(); return $store; } function RegistryMonoState() { $this->_store =& $this->_initRegistry(); } function isValid($key) { return array_key_exists($key, $this->_store); } function &get($key) { if (array_key_exists($key, $this->_store)) return $this->_store[$key]; } function set($key, &$obj) { $this->_store[$key] =& $obj; } }
initRegistry()方法包含一个初始化为数组的静态变量。这个静态变量通过引用返回。在构造函数中$_store实例变量被赋于通过initRegistry()函数返回的引用——即静态数组。好!一个PHP4的类静态变量产生了。
出处:phpchina
责任编辑:bluehearts
上一页 php设计模式介绍之注册模式 [4] 下一页 php设计模式介绍之注册模式 [6]
◎进入论坛网络编程版块参加讨论
|