以前做对外做项目的时候,部门大致分为需求组,美工组,代码组,客户找到需求人员讨论需求,找到美工人员讨论页面,找到代码人员讨论功能。
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来说比较膨胀,但如果与模板模式结合使用,确实是相当不错的高内聚模式,写完之余,感觉此模式与之前的中介者模式有几分想象,但认真再回头看中介者模式之后,还是发现有很大的不同,大家可以看后作下对比。