您的位置:首页 > 其它

【命令模式】设计模式之命令模式【原创】

2017-07-21 16:27 363 查看
摘要:主要是参考列旭松、陈文著的《PHP核心技术与最佳实践》的2.1节。

1.1 简介

命令模式:
将一个请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化。对请求排队或记录请求日志,以及支持撤销的操作。

命令模式以松散耦合主题为基础,发送消息、命令和请求,或通过一组处理程序发送任意内容。每个处理程序都会自行判断自己能否处理请求。如果可以,该请求被处理,进程停止。您可以为系统添加或移除处理程序,而不影响其他处理程序。


1.2 命令模式的角色

命令模式的五种角色:

接收者(Receiver):真正执行命令的对象,负责执行与请求相关的操作

命令接口(Command):定义命令的接口,封装execute()、undo()等方法

具体命令(ConcreteCommand):命令接口实现对象,实现命令接口中的方法,通常会持有接收者,并调用接收者的功能来完成命令要执行的操作

请求者(Invoker):要求命令对象执行请求,通常会持有命令对象,包含Command接口变量

客户端(Client):创建具体的命令对象

如下是命令模式的类图:




1.3 命令模式的优缺点

命令模式的优点:

降低系统的耦合度

新的命令可以很容易地加入到系统中

可以比较容易地设计一个组合命令

调用同一方法实现不同的功能

命令模式的缺点:

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

1.4 具体例子

举个具体的例子,去餐馆吃饭,餐馆存在顾客、服务员、厨师三个角色,作为顾客,只需要列出菜单,传给服务员,服务员通知厨师去实现,而作为服务员,只需要调用准备饭菜这个方法(对厨师通知饭菜),厨师听到要炒菜的请求,立刻去炒。

先来实现命令模式的接收者(在这里即厨师):

2_6_Restaurant\Cook.php:

1
<?php
2
/**
3
* 厨师类,实现炒和煮的方法,即命令模式的命令接受者与执行者
4
*/
5
6
/**
7
* 厨师类,命令接受者与执行者
8
* Class Cook
9
*/
10
class Cook
11
{
12
   public function meal()
13
   {
14
       echo '番茄炒鸡蛋' . PHP_EOL;
15
   }
16
17
   public function drink()
18
   {
19
       echo '紫菜蛋花汤' . PHP_EOL;
20
   }
21
22
   public function ok()
23
   {
24
       echo '完毕' . PHP_EOL;
25
   }
26
}
27

然后实现命令接口:2_6_Restaurant\Command.php:
<?php
/**
* 命令接口
*/

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


接着实现具体的命令(在这里即服务员向厨师通知的具体命令):

2_6_Restaurant\MealCommand.php:

1
<?php
2
/**
3
* 服务员通知厨师做炒菜的命令类,命令模式中的具体命令之一
4
*/
5
6
require_once 'Command.php';
7
8
/**
9
* 服务员通知厨师做炒菜的命令类
10
* Class MealCommand
11
* @package Cook
12
*/
13
class MealCommand implements Command
14
{
15
   private $cook;
16
17
   /**
18
    * 绑定命令接收者(厨师)
19
    * MealCommand constructor.
20
    * @param cook $cook
21
    */
22
   public function __construct(cook $cook)
23
   {
24
       $this->cook = $cook;
25
   }
26
27
   /**
28
    * 让厨师执行炒菜的命令
29
    */
30
   public function execute()
31
   {
32
       $this->cook->meal();
33
   }
34
}
以及还有煮汤的具体命令:2_6_Restaurant\DrinkCommand.php:
<?php
/**
* 服务员通知厨师煮汤的命令类,命令模式中的具体命令之一
*/

/**
* 服务员通知厨师煮汤的命令类
* Class DrinkCommand
* @package Cook
*/
class DrinkCommand implements Command
{
private $cook;

/**
* 绑定命令接收者(厨师)
* MealCommand constructor.
* @param cook $cook
*/
public function __construct(cook $cook)
{
$this->cook = $cook;
}

/**
* 让厨师执行煮汤的命令
*/
public function execute()
{
$this->cook->drink();
}
}


最后是命令模式的请求者(在这里即顾客点菜):

2_6_Restaurant\CookControl.php:

1
<?php
2
/**
3
* 顾客点菜类,命令模式的请求者
4
*/
5
6
class CookControl
7
{
8
   private $mealcommand;
9
   private $drinkcommand;
10
11
   /**
12
    * 将命令发送者绑定到命令接收器上面来
13
    * @param Command $mealcommand
14
    * @param Command $drinkcommand
15
    */
16
   public function AddCommand(Command $mealcommand, Command $drinkcommand)
17
   {
18
       $this->mealcommand = $mealcommand;
19
       $this->drinkcommand = $drinkcommand;
20
   }
21
22
   public function callmeal()
23
   {
24
       $this->mealcommand->execute();
25
   }
26
27
   public function calldrink()
28
   {
29
       $this->drinkcommand->execute();
30
   }
31
32
}

命令模式的代码已经完成,可以写个代码测试一下,即模拟一下顾客点菜(客户端):2_6_Restaurant\example.php:
<?php
/**
* 模拟顾客点了一个菜和一个汤
*/

// 采用自动载入类,不用手动去require所需的类文件
spl_autoload_register('autoload');

function autoload($class)
{
require __DIR__.'/'.$class.'.php';
}

$control = new CookControl();
$cook = new Cook();
$mealcommand = new MealCommand($cook);
$drinkcommand = new DrinkCommand($cook);
$control->AddCommand($mealcommand, $drinkcommand);
$control->callmeal();
$control->calldrink();


运行:
番茄炒鸡蛋
紫菜蛋花汤
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息