以前做对外做项目的时候,部门大致分为需求组,美工组,代码组,客户找到需求人员讨论需求,找到美工人员讨论页面,找到代码人员讨论功能。
class="php"><?php abstract class Group { public abstract function find(); public abstract function add(); public abstract function delete(); public abstract function change(); public abstract function plan(); } class RequirementGroup extends Group{ public function find() { echo "找到需求组\n"; } public function add() { echo "客户要求增加一个需求\n"; } public function delete() { echo "客户要求取消一个需求\n"; } public function change() { echo "客户要求改变一个需求\n"; } public function plan() { echo "客户要求需求变更计划\n"; } } class PageGroup extends Group{ public function find() { echo "找到美工组\n"; } public function add() { echo "客户要求增加一个页面\n"; } public function delete() { echo "客户要求取消一个页面\n"; } public function change() { echo "客户要求改变一个页面\n"; } public function plan() { echo "客户要求页面变更计划\n"; } } $rg = new RequirementGroup(); $rg->find(); $rg->add(); $rg->plan(); ?> 运行结果: 找到需求组 客户要求增加一个需求 客户要求需求变更计划
感觉良好啊,但如果你是客户你每次都要先找到人,再告诉他该怎么做,再确定他的方案,你是不是会觉得你的钱花的不值。客户就只想我要这么做,其它的他都不管,你给我实现就行。这就像是下达命令。那让我们用命令模式来重构一下,类图如下:
创建一个Invoker类,相当于项目负责人的角色,客户直接与Invoker交涉,由Invoker再根据项目的情况下达所需的命令,将经常重复的命令封装以加快效率。在原有的代码基础再加上如下代码:
class CodeGroup extends Group{ public function find() { echo "找到代码组\n"; } public function add() { echo "客户要求增加一个功能\n"; } public function delete() { echo "客户要求取消一个功能\n"; } public function change() { echo "客户要求改变一个功能\n"; } public function plan() { echo "客户要求功能变更计划\n"; } } abstract class Command { protected $rg = null; protected $pg = null; protected $cg = null; public function __construct() { $this->rg = new RequirementGroup(); $this->pg = new PageGroup(); $this->cg = new CodeGroup(); } abstract public function execute(); } class AddRequirementCommand extends Command{ public function execute() { $this->rg->find(); $this->rg->add(); $this->rg->plan(); } } class DeleteRequirementCommand extends Command{ public function execute() { $this->rg->find(); $this->rg->delete(); $this->rg->plan(); } } class Invoker { private $command; public function setCommand( $command ) { $this->command = $command; } public function action() { $this->command->execute(); } } $invoker = new Invoker(); $addRequirementCommand = new AddRequirementCommand(); $invoker->setCommand($addRequirementCommand); $invoker->action(); $deleteRequirementCommand = new DeleteRequirementCommand(); $invoker->setCommand($deleteRequirementCommand); $invoker->action(); 运行结果: 找到需求组 客户要求增加一个需求 客户要求需求变更计划 找到需求组 客户要求取消一个需求 客户要求需求变更计划 [Finished in 0.2s]
?
?
命令模式的定义
高内聚的模式,将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。命令模式有三种角色构成:
1、Receive接收者角色
该角色就是干活的角色,命令传递到这里是应该被执行的,具体到我们上面的例子中就是Group的三个实现类。
2、Command命令角色
需要执行的所有命令都在这里声明
3、Invoker调用者角色
接收到命令,并执行命令。
?
?
命令模式的优点
1、类间解耦
调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只须调用Command抽象类的execute以夷伐夷可以,不需要了解到底哪个接收者执行。
2、可扩展性
Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合。
3、命令模式结合其他模式会更优秀
命令模式可以结合责任链模式,实现命令族解析任务;结合模式方法模式,则可以减少Command子类的膨胀问题。
?
?
命令模式的缺点
请看Command的子类,如果有N个命令,问题就出来了。Command的子类就可不是几个,而是N个.这个类膨胀得非常大,这个就需要读者在项目中慎重考虑使用。
?
?
命令模式的扩展
客户需求的多样化
客户有个需求,它既需要增加一个页面,同时又要增加一个功能,想想,如果是老方法,那么客户需要先后找三个组的人员,而用命令模式,只需更改一下添加需求命令类
class AddRequirementCommand extends Command{ public function execute() { $this->rg->find(); $this->rg->add(); $this->pg->add(); $this->cg->add(); $this->rg->plan(); } }
?
个人感觉命令模式如果独立存在确实对于php来说比较膨胀,但如果与模板模式结合使用,确实是相当不错的高内聚模式,写完之余,感觉此模式与之前的中介者模式有几分想象,但认真再回头看中介者模式之后,还是发现有很大的不同,大家可以看后作下对比。