最近在作O2O平臺的接入,由於發現以前公司的代碼裏已經有了某家開放平臺的接入代碼,若是我再往原先的控制器上加入邏輯代碼,整個控制器的耦合度會很是高。加上每一個平臺有本身的簽名驗證算法,把加解密的方法寫到平臺的接入控制器裏當然好,可是仍是有耦合度問題。所以個人作法是先實現目前手上須要的功能,稍後會用面向對象的方法寫一個抽象類,而後用對應平臺的子類實現相應平臺所須要的業務邏輯代碼。javascript
在寫的過程當中,發現如今框架中使用的YiiMongoDbSuite爲模型類實現的一個單例模式頗有意思,遂決定使用一樣的寫法實現我所須要的平臺接入類。在這裏我將這種寫法略微總結一下。爲了方便,例子中的變量名都使用YiiMongoDbSuite拓展中的變量名了。php
父類(抽象類)中定義一個私有的靜態變量$_model
,類型爲數組,用來保存子類實例化後的結果。java
父類實現一個靜態的公共函數model()
,用於生成子類的實例化並保存在$_model
,傳參爲類名__CLASS__
。算法
子類中一樣實現靜態公共函數model()
,直接返回繼承的父類的model()
方法結果。數組
具體仍是看實現的代碼。框架
父類(抽象類)函數
<?php abstract class Father { public function __construct() {} private static $_models = array(); public static function model($className = __CLASS__) { if (isset(self::$_models[$className])) { return self::$_models[$className]; } else { $model = self::$_models[$className] = new $className(null); return $model; } } }
子類測試
<?php class Child extends Father { public static function model($className=__CLASS__) { return parent::model($className); } public function test() { echo 'i am child!'."\n"; } }
測試代碼ui
<?php var_dump(Child::model()); Child::model()->test(); // 嘗試用一樣的方法生成一個實例並打印 var_dump(Chils::model()); // 直接用new關鍵字生成一個實例並打印 var_dump(new Child());
結果code
object(Putao)#1 (0) {} i am child! object(Putao)#1 (0) {} object(Putao)#2 (0) {}
能夠注意到,使用Child::model()
生成的實例ID相同,而直接經過new Child()
生成的實例ID爲2。
固然,也能夠把父類的__constract()
方法改成私有方法,這樣new
關鍵字就失效了,只能經過Child::model()
這樣的方式實例化子類。