淺談PHP面向物件程式設計(九)
9.0 設計模式
在編寫程式時經常會遇到一此典型的問題或需要完成某種特定需求,設計模式就是針對這些問題和需求,在大量的實踐中總結和理論化之後優選的程式碼結構程式設計風格,以及解決問題的思考方式。
設計模式就像是經典的棋譜。不同的棋局,使用不同的棋諧,免得自己再去思考和模索。本節將針對PHP應用程式中最常用的兩種設計模式進行詳細講解。
9.1 單例模式
單例模式是PHP中的一種設計模式,它是指在設計一個類時,需要保證在整個程式執行期間針對該類只存在一個例項物件。
就像世界上只有一個月亮,假設現在要設計一個類表示月亮,該類只能有一個例項物件,否則就違背了事實。
在講解單例設計模式之前,通過一個案例來演示在什麼情況時需要使用單例模式,如例9-23 所示
例9-23
1 <?php
2 class dbHelper{
3 private $conn = null; 4 public function __construct(){ 5 //開啟一個到 MySQL 伺服器的連線 6 $this->conn = mysql_connect("localhost","root",""); 7 echo "得到一個conn<br/>"; 8 } 9 } 10 $db1 = new dbHelper(); 11 $db2 = new dbHelper(); 12 if($db1 === $db2){ 13 echo "一個物件<br/>"; 14 } else { 15 echo "兩個物件<br/>"; 16 } 17 ?>
執行結果
得到一個conn
得到一個conn
兩個物件
從上例中可以看出,例項化類dbHelper的兩個物件請求的資料庫連線是兩個不同的連線,而在實際開發中,有時會有這樣的需求,
在一次HTTP 請求中,保證某個類的物件例項只能有一個。這樣可以節省資源開銷,此時可以使用單例模式。
單例模式(Singleton)用於為一個類生成一個唯一的物件。(請記住名詞 “”三私一公“”)
私有靜態屬性
私有構造方法
私有克隆方法
公有靜態呼叫隊象方法
將上面的dbHelper 類使用單例模式來實現,如例9-24所示
例9-24
<?php
class dbHelper{
private static $instance = null;//定義一個私有的靜態屬性$instance //宣告一個構造方法 private function __construct(){ $this->conn = mysql_connect("localhost","root",""); echo "得到一個conn<br/>"; } //只有通過這個方法才能返回本類的物件,該方法是靜態方法 public static function getInstance(){ //如果本類中的$instance為空,說明它還沒有被例項化過 if(self::$instance == null){ self::$instance = new self();//例項化本類物件 } return self::$instance;//返回本類的物件 } //阻止使用者複製物件例項 public function __clone(){ } } $db1 = dbHelper::getInstance(); $db2 = dbHelper::getInstance(); if($db1 === $db2){ echo "同一個物件"; }else{ echo "不是同一個物件"; } ?>
執行結果
得到一個conn
同一個物件
在上例中,dbHelper類的構造方法使用了private 關鍵字進行了修飾,即不能在類定義之外使用new來建立物件。
如此一來就只能通過類 名直接呼叫getinstance0靜態方法來建立物件。在第3行程式碼聲明瞭一個私有的靜態屬性$instance.
將例項化的物件賦值給它,再判斷該屬性,如果已經有值,就直接返回,如果其值為null, 就先例項化物件,這樣就能保證dbHelper類只能被例項化一次。
最後增加了一個私有的魔術方法_ clone0. 用於防止使用者通過clone方法複製物件。
9.2 工廠模式
工廠模式的作用就是“生產”物件。工廠方法的引數是要生成物件的類名。
為了方便理解工廠模式的作用,接下來通過一個案例來演示如何使用工廠模式獲取MySQL和sQLite的驅動物件。
首先在根目錄下建立MySQLphp檔案。示例程式碼如下:
1 <?php
2 class MySQL{ 3 4 //操作SQL的驅動類 5 6 }
然後在根目錄下建立SQLite.php檔案。示例程式碼如下:
1 <?php
2 class SQLite{
3 4 //操作SQLite的驅動類 5 6 }
最後定義一個工廠方法來獲取各驅動物件,程式碼如例9-25所示
例9-25
1 <?php
2 header('Content-Type: textml;charset=utf-8');
3 class Db{ 4 //工廠方法 5 public static function factory($type){ 6 if (include_once $type . '.php') { 7 $classname = $type; 8 return new $classname(); 9 } else { 10 echo "出錯了!"; 11 } 12 } 13 } 14 //獲取MySQL驅動物件 15 $mysql = Db::factory('MySQL'); 16 //獲取SQLite驅動物件 17 $sqlite = Db::factory('SQLite'); 18 var_dump($mysql); 19 var_dump($sqlite); 20 ?>
執行結果
object (MySQL) [1]
object (SQLite) [2]
上例中,第5行程式碼定義了一個靜態方法factor(), 這就是工廠方法,該方法的引數為類名。
第6- 11行程式碼用於判斷類名與引數是否相同,如果相同則建立該類的物件,否則輸出“出錯了!”。
第15 17行程式碼分別呼叫factory()方法獲取對應的驅動物件。
從執行結果可以看出,工廠方法成功地建立了兩個驅動類物件。