这篇来简介一个命令模式。假如有这样的一个场景,项目组有需求组,美工组合代码组,需求组负责需求分析,美工组负责页面设计和美化,代码组负责编码和实现需求的逻辑。项目组接了一个项目,客户需要分别和需求组,美工组,代码组进行沟通,讨论需求找需求组,讨论页面找美工组,讨论实现逻辑找代码组。但是我们都知道,在开发中,有时候客户需要经常进行修改,客户需要来来回回的和这三个组进行讨论,客户每次修改相应的东西叫一个组过去,布置任务,然后出计划,每次都这样,双方都比较烦。这时候出现了命令模式,项目中出现一个接头人,客户告诉他怎么做,他复制去执行,客户告诉做什么就做什么。于是设计下面的类图:
Command抽象类只有一个方法execute,其作用就是执行命令,子类非常坚决的实现该命令,与军队中类似,上级军官给士兵发布命令,士兵就去执行。比如客户发送一个山村页面的命令,接头人负责人Invoker接收到命令后,立刻执行DeletePageCommand的execute方法。对类图中简单说明:
Command抽象类:客户发给我们的命令,定义三个工作组的成员变量,供子类使用;定义一个抽象方法execute,由子类来实现。
Invoker实现类:项目接头负责人,setCommand接收客户发给我们的命令,action方法是执行客户的命令
其中,Command抽象类是整个扩展的核心。
下面进行代码的实现:
1,定义一个抽象类,里面提取出来的抽象方法
package com.jack.command;
/**
* Created by jack on 2017/8/4.
* 抽象组
*/
public abstract class Group {
//甲乙双方分开办公,如果需要和某个组讨论,需要先找到这个组
public abstract void find();
//被要求增加功能
public abstract void add();
//被要求删除功能
public abstract void delete();
//被要求修改功能
public abstract void change();
//别要求给出所有变更的计划
public abstract void plan();
}
2,三个组分别实现上面的抽象类,表示需求的变化,组的具体实现行为
需求组:
package com.jack.command;
/**
* Created by jack on 2017/8/4.
* 需求组
*/
public class RequirementGroup extends Group{
/**
* 客户要求需求组过去和他们谈
*/
@Override
public void find() {
System.out.println("找到需求组....");
}
/**
* 客户要求增加一项需求
*/
@Override
public void add() {
System.out.println("客户要求增加一项需求.....");
}
/**
* 客户要求删除一项需求
*/
@Override
public void delete() {
System.out.println("客户要求删除一项需求.....");
}
/**
* 客户要求修改一项需求
*/
@Override
public void change() {
System.out.println("客户要求修改一项需求.....");
}
/**
* 客户要求需求变更计划
*/
@Override
public void plan() {
System.out.println("客户要求需求变更计划.....");
}
}
美工组:
package com.jack.command;
/**
* Created by jack on 2017/8/4.
* 美工组
*/
public class PageGroup extends Group{
/**
* 找到美工组
*/
@Override
public void find() {
System.out.println("找到美工组....");
}
/**
* 客户要求增加一个页面
*/
@Override
public void add() {
System.out.println("客户要求增加一个页面.....");
}
/**
* 客户要求删除一个页面
*/
@Override
public void delete() {
System.out.println("客户要求删除一个页面.....");
}
/**
* 客户要求修改一个页面
*/
@Override
public void change() {
System.out.println("客户要求修改一个页面.....");
}
/**
* 客户要求页面变更计划
*/
@Override
public void plan() {
System.out.println("客户要求页面变更计划.....");
}
}
代码组:
package com.jack.command;
/**
* Created by jack on 2017/8/4.
* 代码组
*/
public class CodeGroup extends Group{
/**
* 客户要求代码组过去和他们谈
*/
@Override
public void find() {
System.out.println("找到代码组....");
}
/**
* 客户要求增加一项功能
*/
@Override
public void add() {
System.out.println("客户要求增加一项功能.....");
}
/**
* 客户要求删除一项功能
*/
@Override
public void delete() {
System.out.println("客户要求删除一项功能.....");
}
/**
* 客户要求修改一项功能
*/
@Override
public void change() {
System.out.println("客户要求修改一项功能.....");
}
/**
* 客户要求代码变更计划
*/
@Override
public void plan() {
System.out.println("客户要求代码变更计划.....");
}
}
3,定义命令抽象类Command
package com.jack.command;
/**
* Created by jack on 2017/8/4.
* 命令抽象类
*/
public abstract class Command {
//把三个组都定义好,子类可以直接使用
protected RequirementGroup rg = new RequirementGroup();//需求组
protected PageGroup pg = new PageGroup();//美工组
protected CodeGroup cg = new CodeGroup();//代码组
//需要做的事情
public abstract void execute();
}
4,定义两个测试的命令实现类
增加需求命令:
package com.jack.command;
/**
* Created by jack on 2017/8/4.
* 增加需求命令
*/
public class AddRequirementCommand extends Command{
/**
* 执行增加一项需求的命令
*/
@Override
public void execute() {
//找到需求组
super.rg.find();
//增加一份需求
super.rg.add();
//给出计划
super.rg.plan();
}
}
删除页面命令:
package com.jack.command;
/**
* Created by jack on 2017/8/4.
* 删除页面的命令
*/
public class DeletePageCommand extends Command{
/**
* 执行一个删除页面的命令
*/
@Override
public void execute() {
//找到页面组
super.pg.find();
//删除一个页面
super.pg.delete();
//给出计划
super.pg.plan();
}
}
5,定义一个命令接收的负责人Invoker
package com.jack.command;
/**
* Created by jack on 2017/8/4.
* 负责人
*/
public class Invoker {
//定义命令对象,执行什么命令
private Command command;
public Command getCommand() {
return command;
}
public void setCommand(Command command) {
this.command = command;
}
/**
* 执行客户的命令
*/
public void action(){
this.command.execute();
}
}
6,测试代码如下:
package com.jack.command;
/**
* Created by jack on 2017/8/4.
*/
public class MainTest6 {
public static void main(String[] args) throws CloneNotSupportedException {
//定义接头人
Invoker ls = new Invoker();
//客户要求增加一项需求
System.out.println("------------客户要求增加一项需求---------------");
//客户给我们下命令来
Command command = new AddRequirementCommand();
//接头人接收到命令
ls.setCommand(command);
//接头人执行命令
ls.action();
}
}
运行测试程序,输出如下:
------------客户要求增加一项需求---------------
找到需求组....
客户要求增加一项需求.....
客户要求需求变更计划.....
现在客户不需要知道到底是谁来执行修改的,上面的就是一个命令模式。
命令模式是一个高内聚的模式,将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。命令模式的通用类图如下:
上面的类图,我们看到三个角色
Receive接收者:该角色就是干活的角色,命令传递到这里应该被执行的,具体到我们上面的例子中就是Group的三个实现类
Command命令角色:需要执行的所有命令都在这里声明
Invoker调用者角色:接收到命令,并执行命令
命令模式的优点:
1)类间解耦,调用者角色与接收者角色之间没有任何的依赖关系,调用者实现功能时只需要调用Command抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。
2)可扩展性,Command的子类可以非常容易的扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合。
3)命令模式结合其他模式会更优秀,命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少Command资料的膨胀问题。
命令模式的缺点:
命令模式也是有缺点的,看Command的子类:如果有N个命令,问题就出来了,Command的子类就可不是几个,而是N个,这个类膨胀得非常大,在使用时需要慎重。
代码地址:https://github.com/wj903829182/springboot/tree/master/designpattern