單例模式被認爲是職責模式,這是由於它將建立對象的控制權委託到一個單一的訪問點上.在任什麼時候候,應用程序中都只有這個類僅有的一個實例存在.php
全部的單例類至少擁有如下三種公共元素:mysql
1.它們必須擁有一個構造函數,而且必須被標記爲private.sql
2.它們擁有一個保存類的實例的靜態成員變量.數據庫
3.它們擁有一個訪問這個實例的公共的靜態方法.編程
和普通類不一樣的是,單例類不能在其餘類中直接實例化.單例類只能被其自身實例化.要得到這種限制效果,__contruct()方法必須被標記爲private.若是試圖用private構造函數構造一個類,就會獲得一個可訪問性級別的錯誤.ide
要讓單例類起做用,就必須使其爲其餘類提供一個實例,用他調用各類方法.單例類不會建立實例副本,而是會向單例類內部存儲的實例返回一個引用.結果是單例類不會重複佔用內存和系統資源,從而讓應用程序的其餘部分更好地使用這些資源.做爲這-模式的一部分,必須建立一個空的私有的__clone()方法,以防止對象被複制或者克隆.函數
返回實例引用的這個方法一般被命名爲getInstance().這個方法必須是靜態的,並且若是它尚未實例化,就必須進行實例化.getInstance()方法經過使用instanceof操做符和self關鍵字,能夠檢測到類是否已經被初始化.若是保存實例靜態成員爲空或者還不是類自身的一個實例,那麼這個實例將會被建立並保存到存放實例的變量中.this
使用單例類:spa
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');
工廠類是指包含了一個專門用來建立其餘對象的方法的類.工廠類在多態性編程實踐中是相當重要的.它容許動態地替換類,修改配置,而且一般會使應用程序更加靈活.code
一般,工廠模式有一個關鍵的構造,即根據通常原則被命名爲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的規範來編寫,而實現類將負責執行用來操做特定數據庫的查詢.