《PHP设计模式介绍》第四章 单件模式(3)_PHP教程

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

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

PHP5中的单件模式

PHP5中更容易实现单件模式,PHP5对于类内部变量和函数的访问控制被加强了。将DbConn::_construct()构造方法设置为私有(private),这个类就不能被直接实例化。用UML图表示,PHP5的DbConn单件模式如下:

组合使用静态方法和静态变量保持这个实例,并且设置构造函数为私有,以防止直接实例化类而创建实例,代码如下:

class DbConn {
/**
* static property to hold singleton instance
*/
static $instance = false;
/**
* constructor
* private so only getInstance() method can instantiate
* @return void
*/
private function __construct() {}
/**
* factory method to return the singleton instance
* @return DbConn
*/
public function getInstance() {
if (!DbConn::$instance) {
DbConn::$instance = new DbConn;
}
return DbConn::$instance;
}
}

结论

现在你已经看到几种单件设计模式的实现方式了,当你着眼于实现这个设计模式时候,我们要仔细权衡考虑。

首先,一个单件对象不是一个“很好的”全局变量。举例来说,如果一个方法需要一个单件对象,更显而易见的用法是把它当作一个参数传递来使用。

同样,因为它可以在“全局”得到使用,你很容易就会将所有种类的“常用函数”放置到一个单件类中。这个是你需要避免的,需要的时候,你才把函数封装单件类中。

Monostate Pattern(单态模式):类单件模式

有时候,我们需要这样一个类,所有类的实例都共享它的全局状态――换句话说,它所产生的任何实例返回严格一致的信息。和单件模式类似,这是一种叫做MonoState(单态)的模式。在PHP中,你使用一种优美的引用技巧来绑定全局数据,通过把一个全局变量绑定到一个实例变量来实现MonoState。

举个例子,让我们创建一个全局应用配置类。无论你用MonoState类的哪个实例,你都能得到同样的值。

下面的测试代码用来验证次功能:

// PHP4
function TestApplConfig() {
$this->assertIsA(
$obj1 =& new ApplicationConfig, ApplicationConfig);
$this->assertIsA(
$obj2 =& new ApplicationConfig, ApplicationConfig);
$test_val = /path/to/cache.rand(1,100);
$obj1->set(cache_path, $test_val);
$this->assertEqual($test_val, $obj2->get(cache_path));
}

下面这段代码实现了MonoState:

class ApplicationConfig {
var $_state;
function ApplicationConfig() {
$key = __stealth_singleton_state_index__;
if (!(array_key_exists($key, $GLOBALS)
&& is_array($GLOBALS[$key]))) {
$GLOBALS[$key] = array();
}
$this->_state =& $GLOBALS[$key];
}
function set($key, $val) {
$this->_state[$key] = $val;
}
function get($key) {
if (array_key_exists($key, $this->_state)) {
return $this->_state[$key];
}
}

这个技巧能够在任何PHP的自动全局(superglobal)数组使用,尤其在用户消息队列$_SESSION中有很显著的效果。MonoState能通过你的代码为用户存储一系列的使用信息(你要显示的信息可能是从另外一个页面传入的)。$_SESSION是一个存储这些信息的好地方,以方便这些信息在页面跳转后能持续使用。

这个技巧的核心是$this->state =& $GLOBALS[$key]; 。在确定$GLOBALS[$key]是一个数组后,代码绑定一个全局数组的引用给类变量$this->state。从而,任何$this->state的改变都自然而言地同步到全局数组,包括类的其它实例。
Test创建了MonoStatel类的两个不同实例,改变其中一个,验证另外一个是否也一起被改变了。这段代码很简单的选择了这个静态数组$instancede的第一个元素,用来保持单件DbConns实例的引用。Zend 1引擎在PHP4中不能存储静态变量的引用 (请看http://www.php.net/manual/en/language.variables.scope.php#AEN3609)。使用一个工作区存储静态数组,并且将这个单件实例的引用放置到一个已知的数组中。getInstance()方法如下:提示在DbConn的构造函数中,你可能对$fromGetInstance的默认参数感到疑惑。在对象被直接实例化时,它能够提供(很微弱的)保护:除非这个默认值变成e (在PHP的数学常量中 M_E = 2.718281828459),否则这段代码会报错。这段代码直接创建了一个 DbConn 的实例,将会引起PHP报错。为了让代码更稳定,我们用PCRE正则表达式来匹配报错信息。(显示报错信息的确切措词并不重要。)

分享:《PHP设计模式介绍》第二章 值对象模式
在所有的最简单的程序中,大多数对象都有一个标识,一个重要的商业应用对象,例如一个Customer或者一个SKU,有一个或者更多的属性---id,name,email地址,这样可以把它从同一个类的其他实例区分开

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