《PHP设计模式介绍》第五章 注册模式(3)_PHP教程

编辑Tag赚U币
教程Tag:暂无Tag,欢迎添加,赚取U币!

推荐:《PHP设计模式介绍》第四章 单件模式
几乎所有面向对象的程序中,总有一两个资源被创建出来,在程序应用中持续被共享使用。例如,这样的一个资源,在一个电子商务程序的数据库连接中使用:这个连接在应用程序启动时初始化,程序于是


initRegistry()方法包含一个初始化为数组的静态变量。这个静态变量通过引用返回。在构造函数中$_store实例变量被赋于通过initRegistry()函数返回的引用——即静态数组。好!一个PHP4的类静态变量产生了。

使用类静态变量的实现:

PHP5中,没有必要自己实现类静态变量,因为PHP5直接支持类静态变量。因此,PHP5简化了实现。而且,PHP5中引用、对象不再有PHP4中的意义,但是assertReference() 处理了这种差别,如果两个变量指向同一个对象句柄也可以通过测试。

以下是为PHP5改写的类似的Registry测试用例。

// PHP5
class RegistryMonoStatePHP5TestCase extends UnitTestCase {
function testRegistryMonoState() {
$this->assertCopy(
$reg = new RegistryMonoState
,$reg2 = new RegistryMonoState);
$this->assertFalse($reg->isValid(‘key’));
$this->assertNull($reg->get(‘key’));
$test_value = new TestObj;
$reg->set(‘key’, $test_value);
$this->assertReference($test_value, $reg2->get(‘key’));
}
}

以下是PHP5版本的使用静态类变量的Registry类。

class RegistryMonoState {
protected static $store = array();
function isValid($key) {
return array_key_exists($key, RegistryMonoState::$store);
}
function get($key) {
if (array_key_exists($key, RegistryMonoState::$store))
return RegistryMonoState::$store[$key];
}
function set($key, $obj) {
RegistryMonoState::$store[$key] = $obj;
}
}

PHP5中用这种方式编码Registry类的一个有趣的效果是你可以用相同的代码使用实例或者静态方法。以下是证明仅仅使用静态方法的测试用例。

class RegistryMonoStatePHP5TestCase extends UnitTestCase {
function testRegistryMonoState() { /*...*/ }
function testRegistryMonoStateStaticCalls() {
$this->assertFalse(RegistryMonoState::isValid(‘key’));
$this->assertNull(RegistryMonoState::get(‘key’));
$test_value = new TestObj; RegistryMonoState::set(‘key’, $test_value);
$this->assertIdentical($test_value, RegistryMonoState::get(‘key’));
}

现在你已经看到在PHP5中的静态调用接口,下面让我们在PHP4中实现相同的接口。在前面的PHP4“静态类变量”部分,实现需要使用“函数静态变量返回引用”来跟踪。PHP4版本的静态调用接口测试与PHP5版本的测试类似。

// PHP4
class RegistryStaticPHP4TestCase extends UnitTestCase {
function testRegistryStatic() {
$this->assertFalse(RegistryStatic::isValid(‘key’));
$this->assertNull(RegistryStatic::get(‘key’));
$test_value = ‘something’; RegistryStatic::set(‘key’, $test_value);
$this->assertReference($test_value, RegistryStatic::get(‘key’));
}
}

以下是符合测试要求的代码实现。

class RegistryStatic {
function &_getRegistry() { static $store = array(); return $store;
}
function isValid($key) {
$store =& RegistryStatic::_getRegistry();
return array_key_exists($key, $store);
}
function &get($key) {
$store =& RegistryStatic::_getRegistry();
if (array_key_exists($key, $store))
return $store[$key];
}
function set($key, &$obj) {
$store =& RegistryStatic::_getRegistry();
$store[$key] =& $obj;
}
}


这个实现方法的重点是getRegistry()方法返回一个对静态数组的引用。

$store =& RegistryStatic::_getRegistry();这一行,在随后的函数中把变量$store通过引用赋给静态数组,允许所有的函数可以静态访问数组,允许所有的方法可以被静态调用。

也可以不使用PHP4“静态类变量跟踪”达到相同的效果:将原先的基于单件模式的Registry类与一个包装类结合以达到允许静态调用。这个类与testRegistryStatic()有相同的测试代码,但是他的实现如下所示:

class RegistryStatic {
function isValid($key) {
$reg =& Registry::getInstance();
return $reg->isValid($key);
}
function &get($key) {
$reg =& Registry::getInstance();
return $reg->get($key);
}
function set($key, &$obj) {
$reg =& Registry::getInstance();
$reg->set($key, $obj);
}
}

结论:

虽然注册模式简化了对大量对象的访问,但是仍然有许多问题——与全局变量联合。你需要确定要求的属性Key在访问之已经被初始化了,而且设置属性的方法可以全局访问,你的对象仍然可能在你的代码的其他部分出乎意料的被替换掉。显然,全局数据非常有好处,方便,但是你需要时刻记住任何全局数据都是有一些不安全的。


内嵌的Registry模式

除了单独使用注册模式——如本章所示,Registry模式与其他对象结合时功能也是非常强大。例如:当对象的创建代价非常昂贵(例如需要查询大量数据库来初始化对象)时,而且对象在这个应用中被使用一次或多次,如果这样,你能创建一个结合了工作模式 (见第三章) 和注册模式 的“Finder”类以获得已经创建的对象的缓存而不用再次创建他们?

以下是一个Contact类,AddressBook类是工厂类。

class AddressBook {
function &findById($id) {
return new Contact($id);
}
}
class Contact {
function Contact($id) {
// expensive queries to create object using $id
}
// ... other methods
}

你可以在AddressBook类中插入Registry模式来提供缓存。代码可以如下所示:

class AddressBook {
var $registry;
function AddressBook() {
$this->registry =& Registry::getInstance();
}
function &findById($id) {
if (!$this->registry->isValid($id)) {
$this->registry->set($id, new Contact($id));
}
return $this->registry->get($id);
}
}

AddressBook类的构造函数将registry绑定到一个实例变量。当创建了一个特定的ID并被findById()方法调用时,Registry被检查以确定对象是否已经被缓存。如果没有,将创建一个新的对象并存储在Registry中。被调用的对象将通过函数从Registry中取出并被返回。

分享:《PHP设计模式介绍》第三章 工厂模式
在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。举例来说, 许多类型对象的创造需

共3页上一页123下一页
来源:模板无忧//所属分类:PHP教程/更新时间:2008-08-22
相关PHP教程