职责和单例模式
单例模式被认为是职责模式,这是因为它将创建对象的控制权委托到一个单一的访问点上.在任何时候,应用程序中都只有这个类仅有的一个实例存在.
所有的单例类至少拥有以下三种公共元素:
1.它们必须拥有一个构造函数,并且必须被标记为private.
2.它们拥有一个保存类的实例的静态成员变量.
3.它们拥有一个访问这个实例的公共的静态方法.
和普通类不同的是,单例类不能在其他类中直接实例化.单例类只能被其自身实例化.要获得这种限制效果,__contruct()方法必须被标记为private.如果试图用private构造函数构造一个类,就会得到一个可访问性级别的错误.
要让单例类起作用,就必须使其为其他类提供一个实例,用他调用各种方法.单例类不会创建实例副本,而是会向单例类内部存储的实例返回一个引用.结果是单例类不会重复占用内存和系统资源,从而让应用程序的其他部分更好地使用这些资源.作为这-模式的一部分,必须创建一个空的私有的__clone()方法,以防止对象被复制或者克隆.
返回实例引用的这个方法通常被命名为getInstance().这个方法必须是静态的,而且如果它还没有实例化,就必须进行实例化.getInstance()方法通过使用instanceof操作符和self关键字,可以检测到类是否已经被初始化.如果保存实例静态成员为空或者还不是类自身的一个实例,那么这个实例将会被创建并保存到存放实例的变量中.
使用单例类:

class Database{ private $_db; static $_instance; private function __construct(){ $this->_db = pg_connect('dbname=example_db'); } private __clone(){}; public static function getInstance(){ if(!(self::$_instance instanceof self)){ self::$_instance = new self(); } return self::$_instance; } public function query($sql){ //使用$this->_db执行一个查询 return pg_query($this->_db,$sql); } } $db = Database::getInstance(); $db->query('SELECT * FROM example_table');
工厂模式
工厂类是指包含了一个专门用来创建其他对象的方法的类.工厂类在多态性编程实践中是至关重要的.它允许动态地替换类,修改配置,并且通常会使应用程序更加灵活.
通常,工厂模式有一个关键的构造,即根据一般原则被命名为factory的静态方法.然而,这只是一种原则,工厂方法可以任意命名.这个静态方法还可以接受任意数量的参数,并且必须返回一个对象.
基本的工厂类:

class MyObject{ //对象将从工厂类返回 } class MyFactory{ public static function factory(){ //返回对象的一个新实例 return new MyObject(); } } $instance = MyFactory::factory();
使用工厂类解析图像文件

<?php interface IImage{ function getHeight(); function getWidth(); function getData(); } class Image_PNG implements IImage{ private $_width,$_height,$_data; public function __construct($file){ $this->_file = $file; $this->_parse(); } private function _parse(){ //完成PNG格式的解析工作 //并填充$_width,$_height和$_data } public function getWidth(){ return $this->_width; } public function getHeight(){ return $this->_height; } public function getData(){ return $this->_data; } } class Image_JPEG implements IImage{ private $_width,$_height,$_data; public function __construct($file){ $this->_file = $file; $this->_parse(); } private function _parse(){ //完成JPEG格式的解析工作 //并填充$_width,$_height和$_data } public function getWidth(){ return $this->_width; } public function getHeight(){ return $this->_height; } public function getData(){ return $this->_data; } } class ImageFactory{ public static function factory($file){ $pathParts = pathinfo($file); switch (strtolower($pathParts['extension'])) { case 'jpg': $ret = new Image_JPEG($file); break; case 'png': $ret = new Image_PNG($file); default: //有问题 } if($ret instanceof IImage){ return $ret; }else{ //有问题 } } } $image = ImageFactory::factory('/path/to/my.jpg'); //$image现在是Image_JPEG类的一个实例 echo $image->getWidth();
上例中,ImageFactory是工厂类,因为它返回了一个类的实例.类的类型是通过调用pathinfo()函数获得的文件拓展名类决定的.由于它是一个工厂类,产生的应用程序不需要知道这些图像解析的细节,需要知道的是工厂返回的对象支持IImage接口.
使用这一技术使得API更加容易调用,这是因为它只有一个类和一个方法.如果不使用工厂模式,API的调用者将需要决定应该调用的类,然后去调用某个特定的类,这样就需要对工厂的行为进行复制.
工厂类解决数据库可移植性问题

interface IDatabaseBindings{ public function userExists($email); } class PGSQL implements IDatabaseBindings{ protected $_connection; public function __construct(){ $this->_connection = pg_connect('dbname=example_db'); } public function userExists($email){ $emailEscaped = pg_escape_string($email); $query = "select 1 from users where email ='".$emailEscaped."'"; if($result = pg_query($query,$this->_connection)){ return (pg_num_rows($result) > 0)?true:false; }else{ return false; } } } class MYSQL implements IDatabaseBindings{ protected $_connection; public function __construct(){ $this->_connection = mysql_connect('localhost'); mysql_select_db('example_db',$this->_connection); } public function userExists($email){ $emailEscaped = mysql_real_escape_string($email); $query = "select 1 from users where email ='".$emailEscaped."'"; if($result = mysql_query($query,$this->_connection)){ return (mysql_num_rows($result) > 0)?true:false; }else{ return false; } } } class DatabaseFactory{ public static function factory(){ $type = loadtypefromconfigfile(); switch ($type) { case 'PGSQL': return new PGSQL(); break; case 'MYSQL': return new MYSQL(); break; } } } //---用法--- $db = DatabaseFactory::factory(); $db->userExists('person@example.com');
以上代码创建一个DatabaseFactory类,它将会实例化并返回与IDatabaseBindings接口兼容的对象.应用程序将会根据IDatabaseBindings的规范来编写,而实现类将负责执行用来操作特定数据库的查询.