最近在作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()
这样的方式实例化子类。