体现SRP(单一职责原则)的两种模式——工厂模式和命令模式

单一职责有两种含义:一是避免相同的职责分散到不同的类中,另一个是避免一个类承担太多职责。遵循单一职责的目的:


(1)可以减少类之间的耦合(模块与模块之间的依赖关系)


减少类之间的耦合,当需求发生变化时,我们只需要修改一个类,从而也就隔离了变化;如果一个类有多个不同职责,它们耦合在一起,当一个职责发生改变时,可能会影响到其他职责。


(2)提高类的复用性


当只需要复用该类的一个职责时,由于与其他类耦合度过多,导致很难分离出。

遵循SRP在代发开发中的应用:

一、工厂模式

工厂模式允许在代码执行时实例化对象。它负责“生产”对象,最简单的工厂就是根据传入的类型名实例化对象。以数据库为例,也许在一个项目中需要不同种类数据库之间的数据交互,我们在之前需要定义多个数据库类,工厂模式的存在是我们可以根据不同的参数类型,实现不同数据库的调用。

首先我们定义一个适配器接口

interface Db_Adapter
{
      /*
       * 数据库连接
       * @param $config 数据库配置
       * @return resource
       * */
      public  function connect($config);//接口的方法不能拥有主体
      /*
       * 执行数据库查询
       * @param string $query 数据库查询SQL字符串
       * @param mixed $handle 连接对象
       * @return resource
       * */
      public function query($query,$handle);
}

这是一个简化的接口,并没有提供具体的方法,其定义了数据库的操作类,这个类实现了Db_Adapter接口

定义Mysql数据库的操作类

class Db_Adapter_Mysql implements Db_Adapter
{
      private $_dblink;//链接数据库字符串标识
      /*
       * @param $config 数据库配置
       * @throw Db_Exception
       * @return resource
       * */
      
      public function connect($config)
      {
            if($this->_dblink = @mysql_connect($config->HOST.(empty($config->PORT)?'':':'.$config->port),$config->USER,$config->PWD,true)) {
                  if(@mysql_select_db($config->database,$config->_dblink)) {
                        return $this->_dblink;
                  } else{
                        throw new Db_Exception(@mysql_error($config->_dblink));
                  }
            }
            // TODO: Implement connect() method.
      }
      
      /*
       * 执行数据库查询
       * @param string $query 数据库查询SQL字符串
       * @param mixed $handle 连接对象
       * @return resource
       * */
public function query($query, $handle) { if ($resource = @mysql_query($query,$handle)) {
return $resource;
}
// TODO: Implement query() method. }}


下面定义一个SQLite数据库的操作类
class Db_Adapter_SQLite implements Db_Adapter
{
      private $_dblink;//链接数据库字符串标识
      /*
       * @param $config 数据库配置
       * @throw Db_Exception
       * @return resource
       * */

      public function connect($config)
      {
            if ($this->_dblink = sqlite_open($config->file,0066,$error)) {
                  return $this->_dblink;
            }
            throw new Db_Exception($error);
            // TODO: Implement connect() method.
      }

      public function query($query, $handle)
      {
            if ($resource = @sqlite_query($query,$handle)) {
                  return $resource;
            }
            // TODO: Implement query() method.
      }
}
现在需要一个数据库操作方法的时候,只需定义一个工厂类

class SqlFactory
{
      public static function factory ($type) {
            if(include_once"Db_Adpater_{$type}.class.php") {
                  $className = 'Db_Adapter_'.$type;
                  return new $className;
            } else {
                  throw new Exception('Driver not found');
            }
       }
}

调用时:

$db = sqlFactory::factory('Mysql');
我们把创建数据库连接这块单独拿出来,程序中的CRUD就不用关心是什么数据库了,只需要规划是哦那个对应的方法即可。工厂方法让具体的对象解放出来,使其不再依赖具体的类,而是抽象。

二、命令模式

设计模式里面的命令模式也是单一职责的体现,命令模式分离“命令的请求者”和“命令的实现者”方面的职责。比如说在一个餐馆里面,有厨师、服务员和顾客三种角色。作为顾客,只需要列出清单,传给服务员,由服务员通知厨师实现。作为服务员,只需要调用饭菜这个方法,厨师收到炒菜的请求,就立刻去做饭。在这里,命令的请求和实现就完成了解耦。

模拟这个过程,首先,定义厨师角色,处理进行实际的炒菜、做汤的操作。

/*
 * 厨师,命令的接收者与执行者
 * */
class Cook
{
      public function meal () {
            echo "aaa",PHP_EOL; //做饭的命令
      }

      public function drink () {
            echo "bbb";//做汤的命令
      }
}

interface Command{ //命令接口
      public function execute();
}

接下来模拟服务员和厨师的过程

//模拟厨师与服务员的过程
class MealCommand implements Command
{
      private $cook;//绑定命令接收者

      public function __construct(Cook $cook)
      {
            $this->cook = $cook;
      }

      public function execute()
      {
            $this->cook->meal();
            // TODO: Implement execute() method.
      }
}

class DrinkCommand implements Command
{
      private $cook;//绑定命令接收者
      public function __construct(Cook $cook)
      {
            $this->cook = $cook;
      }

      public function execute()
      {
            $this->cook->drink();
            // TODO: Implement execute() method.
      }
}

模拟顾客和服务员的过程

class CookControler
{
      private $mealcommand;
      private $drinkcommand;//将命令发送者绑定到命令接收者上面(服务员)
      public function addCommand (Command $mealCommand,Command $drinkCommand) {
            $this->mealcommand = $mealCommand;
            $this->drinkcommand = $drinkCommand;
      }

      public function callMeal () {
            $this->mealcommand->execute();
      }

      public function callDrink () {
            $this->drinkcommand->execute();
      }
}


实现命令模式:

$cook = new Cook();
$mealCommand = new MealCommand($cook);
$drinkCommand = new DrinkCommand($cook);
$cookController = new CookControler();
$cookController->addCommand($mealCommand,$drinkCommand);
$cookController->callDrink();
$cookController->callMeal();
设计模式并非理论的东西,而是来源于生活。在设计模式方面体现的SRP的还有别的(代理模式),SRP是最简单的原则之一,也是最难设计的原则之一。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值