zl程序教程

您现在的位置是:首页 >  后端

当前栏目

PHP设计模式单例模式的继承实现

2023-09-11 14:18:38 时间

最近在做O2O平台的接入,因为发现之前公司的代码里已经有了某家开放平台的接入代码,如果我再往原先的控制器上加入逻辑代码,整个控制器的耦合度会非常高。加上每个平台有自己的签名验证算法,把加解密的方法写到平台的接入控制器里固然好,但是还是有耦合度问题。因此我的做法是先实现目前手上需要的功能,稍后会用面向对象的方法写一个抽象类,然后用对应平台的子类实现相应平台所需要的业务逻辑代码。

在写的过程中,发现现在框架中使用的YiiMongoDbSuite为模型类实现的一个单例模式很有意思,遂决定使用同样的写法实现我所需要的平台接入类。在这里我将这种写法略微总结一下。为了方便,例子中的变量名都使用YiiMongoDbSuite拓展中的变量名了。

 

1.父类(抽象类)中定义一个私有的静态变量$_model,类型为数组,用来保存子类实例化后的结果。

2.父类实现一个静态的公共函数model(),用于生成子类的实例化并保存在$_model,传参为类名__CLASS__

3.子类中同样实现静态公共函数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";

  }

}

 

测试代码:

<?php

var_dump(Child::model());

Child::model()->test();

 

// 尝试用同样的方法生成一个实例并打印

var_dump(Chils::model());

// 直接用new关键字生成一个实例并打印

var_dump(new Child());

 

结果:

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