閱讀原文:http://www.yzswyl.cn/blread-1601.html
今天群裡有個朋友在問“private function __construct() {}”這樣能防止直接new對象嗎?於是呢我也去網上找了篇詳細的資料來分析下,感覺講的還是蠻不錯的,推薦給大家:
單例模式要解決的問題就是“如何讓這個類只有一個執行個體”。
我們的web應用中,大量使用了資料庫連接,如果反覆建立與資料庫的串連必然消耗更多的系統資源。
我們如何解決這個問題,建立唯一的資料庫連接是必要的方式。
我們又如何知道與這個資料庫的串連是否已經建立? 還是需要現在建立?
單例模式可以解決這個問題。
先假設我們需要一個類完成在記憶體中只有一份的功能,我們該如何做呢?
我們一步一步的使用前面學過的知識來寫一個單例的例子。
前面學過,每次用 new 類名 的方式,就可以建立一個對象。我們必須禁止外部程式用 new 類名的方式來建立多個執行個體。
解決辦法是:我們將建構函式設定成 private ,讓建構函式只能在內部被調用,而外部不能調用。這樣,這個類就不能被外部用 new 的方式建立多個執行個體了。
以下是不能被外部用new執行個體化的類。
?
<?class A{ private function __construct(){} }$a = new A();?> |
程式運行結果為:
?
Fatal error: Call to private A::__construct() from invalid context in E:\PHPProjects\test.php on line 6 |
我們已經禁止外部用new執行個體化這個類,我們改如何讓使用者訪問這個類呢?前門堵了,我們需要給使用者留個後門。
解決辦法是:static 修飾的方法,可以不經執行個體化一個類就可以直接存取這個方法。
?
//不能用new執行個體化的類.<br>//static的方法留給外部存取.<br>//在方法內部返回執行個體.<br><br><?class A{ private function __construct(){} static function getClassA(){ $a = new A(); return $a; } }// 看到這裡確實返回的是 A 的執行個體.但不是同一個對象.$a1 = A::getClassA();$a2 = A::getClassA();echo "\$a1 的類是 ".get_class($a1)." , \$a2 是 ".get_class($a1);if($a1 === $a2){ echo "<br> \$a1 \$a2 指向同一對象.";}else{ echo "<br> \$a1 \$a2 不是一個對象.";}?> |
程式運行結果為:
?
$a1 的類是 A , $a2 是 A$a1 $a2 不是一個對象. |
我們已經通過static方法返回了A的執行個體。但還有問題。我們如何保證我們多次操作獲得的是同一個執行個體的呢?
解決辦法:static的屬性在內部也只有一個。static
屬效能有效被靜態方法調用。將這個屬性也設定成private,以防止外部調用。先將這個屬性設定成 null。每次返回對象前,先判斷這個屬性是否為
null 。如果為 null 就建立這個類的新執行個體,並賦值給這個 static 屬性。如果不為空白,就返回這個指向執行個體的 static 屬性。
?
//不能用new執行個體化的類.<br>//static的方法留給外部存取.<br>//在方法內部返回執行個體.<br>//定義靜態屬性保證這個執行個體能被靜態方法調用.<br>//增加判斷部分.<br><br><?class A{ private static $a = null; private function __construct(){} static function getClassA(){ if( null == self::$a){ self::$a = new A(); } return self::$a; } }// 看到這裡確實返回的是 A 的執行個體.但不是同一個對象.$a1 = A::getClassA();$a2 = A::getClassA();echo "\$a1 的類是 ".get_class($a1)." , \$a2 是 ".get_class($a1);if($a1 === $a2){ echo "<br> \$a1 \$a2 指向同一對象.";}else{ echo "<br> \$a1 \$a2 不是一個對象.";}?> |
程式運行結果為:
?
$a1 的類是 A , $a2 是 A$a1 $a2 指向同一對象. |
到此,我們寫了一個最簡單的單例模式 。
現在,你可以嘗試寫一個應用單例設計模式的資料庫連接類。
要記住單例模式的使用效果和書寫方式。
閱讀原文:http://www.yzswyl.cn/blread-1601.html
今天群裡有個朋友在問“private function __construct() {}”這樣能防止直接new對象嗎?於是呢我也去網上找了篇詳細的資料來分析下,感覺講的還是蠻不錯的,推薦給大家:
單例模式要解決的問題就是“如何讓這個類只有一個執行個體”。
我們的web應用中,大量使用了資料庫連接,如果反覆建立與資料庫的串連必然消耗更多的系統資源。
我們如何解決這個問題,建立唯一的資料庫連接是必要的方式。
我們又如何知道與這個資料庫的串連是否已經建立? 還是需要現在建立?
單例模式可以解決這個問題。
先假設我們需要一個類完成在記憶體中只有一份的功能,我們該如何做呢?
我們一步一步的使用前面學過的知識來寫一個單例的例子。
前面學過,每次用 new 類名 的方式,就可以建立一個對象。我們必須禁止外部程式用 new 類名的方式來建立多個執行個體。
解決辦法是:我們將建構函式設定成 private ,讓建構函式只能在內部被調用,而外部不能調用。這樣,這個類就不能被外部用 new 的方式建立多個執行個體了。
以下是不能被外部用new執行個體化的類。
?
<?class A{ private function __construct(){} }$a = new A();?> |
程式運行結果為:
?
Fatal error: Call to private A::__construct() from invalid context in E:\PHPProjects\test.php on line 6 |
我們已經禁止外部用new執行個體化這個類,我們改如何讓使用者訪問這個類呢?前門堵了,我們需要給使用者留個後門。
解決辦法是:static 修飾的方法,可以不經執行個體化一個類就可以直接存取這個方法。
?
//不能用new執行個體化的類.<br>//static的方法留給外部存取.<br>//在方法內部返回執行個體.<br><br><?class A{ private function __construct(){} static function getClassA(){ $a = new A(); return $a; } }// 看到這裡確實返回的是 A 的執行個體.但不是同一個對象.$a1 = A::getClassA();$a2 = A::getClassA();echo "\$a1 的類是 ".get_class($a1)." , \$a2 是 ".get_class($a1);if($a1 === $a2){ echo "<br> \$a1 \$a2 指向同一對象.";}else{ echo "<br> \$a1 \$a2 不是一個對象.";}?> |
程式運行結果為:
?
$a1 的類是 A , $a2 是 A$a1 $a2 不是一個對象. |
我們已經通過static方法返回了A的執行個體。但還有問題。我們如何保證我們多次操作獲得的是同一個執行個體的呢?
解決辦法:static的屬性在內部也只有一個。static
屬效能有效被靜態方法調用。將這個屬性也設定成private,以防止外部調用。先將這個屬性設定成 null。每次返回對象前,先判斷這個屬性是否為
null 。如果為 null 就建立這個類的新執行個體,並賦值給這個 static 屬性。如果不為空白,就返回這個指向執行個體的 static 屬性。
?
//不能用new執行個體化的類.<br>//static的方法留給外部存取.<br>//在方法內部返回執行個體.<br>//定義靜態屬性保證這個執行個體能被靜態方法調用.<br>//增加判斷部分.<br><br><?class A{ private static $a = null; private function __construct(){} static function getClassA(){ if( null == self::$a){ self::$a = new A(); } return self::$a; } }// 看到這裡確實返回的是 A 的執行個體.但不是同一個對象.$a1 = A::getClassA();$a2 = A::getClassA();echo "\$a1 的類是 ".get_class($a1)." , \$a2 是 ".get_class($a1);if($a1 === $a2){ echo "<br> \$a1 \$a2 指向同一對象.";}else{ echo "<br> \$a1 \$a2 不是一個對象.";}?> |
程式運行結果為:
?
$a1 的類是 A , $a2 是 A$a1 $a2 指向同一對象. |
到此,我們寫了一個最簡單的單例模式 。
現在,你可以嘗試寫一個應用單例設計模式的資料庫連接類。
要記住單例模式的使用效果和書寫方式。