職責和單例模式
單例模式被認為是職責模式,這是因為它將創建對象的控制權委托到一個單一的訪問點上.在任何時候,應用程序中都只有這個類僅有的一個實例存在.
所有的單例類至少擁有以下三種公共元素:
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的規范來編寫,而實現類將負責執行用來操作特定數據庫的查詢.