命令模式是一种行为型模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
作为开发人员经常会接到需求,然后根据需求进行代码编写,当然需求一般都是先产品做好原型图,UI再设计,然后前端后端开发,最后通过测试进行测试。如果这一天需求发生了变化,也就是所谓的命令。让ui改变一下图。或者让开发人员增加一个新功能。那么有了下面这样的操作。
Group是对不同人员的抽象,他们的子类包含了产品经理、ui以及开发人员。
public abstract class Group {
//甲乙双方分开办公,你要和那个组讨论,你首先要找到这个组
public abstract void find();
//被要求增加功能
public abstract void add();
//被要求删除功能
public abstract void delete();
//被要求修改功能
public abstract void change();
//被要求给出所有的变更计划
public abstract void plan();
}
复制
ProductManagerGroup、UiGroup、CodeGroup分别表示产品组、UI组以及开发组
public class ProductManagerGroup extends Group{
//客户要求需求组过去和他们谈
@Override
public void find() {
System.out.println("找到需求组...");
}
//客户要求增加一项需求
@Override
public void add() {
System.out.println("客户要求增加一项需求...");
}
@Override
//客户要求修改一项需求
public void change() {
System.out.println("客户要求修改一项需求...");
}
//客户要求删除一项需求
@Override
public void delete() {
System.out.println("客户要求删除一项需求...");
}
//客户要求出变更计划
@Override
public void plan() {
System.out.println("客户要求需求变更计划...");
}
}
复制
public class UiGroup extends Group{
//客户要求需求组过去和他们谈
@Override
public void find() {
System.out.println("找到美工组...");
}
//客户要求增加一项需求
@Override
public void add() {
System.out.println("客户要求增加一项需求...");
}
@Override
//客户要求修改一项需求
public void change() {
System.out.println("客户要求修改一项需求...");
}
//客户要求删除一项需求
@Override
public void delete() {
System.out.println("客户要求删除一项需求...");
}
//客户要求出变更计划
@Override
public void plan() {
System.out.println("客户要求需求变更计划...");
}
}
复制
public class CodeGroup extends Group{
//客户要求需求组过去和他们谈
@Override
public void find() {
System.out.println("找到开发组...");
}
//客户要求增加一项需求
@Override
public void add() {
System.out.println("客户要求增加一项需求...");
}
@Override
//客户要求修改一项需求
public void change() {
System.out.println("客户要求修改一项需求...");
}
//客户要求删除一项需求
@Override
public void delete() {
System.out.println("客户要求删除一项需求...");
}
//客户要求出变更计划
@Override
public void plan() {
System.out.println("客户要求需求变更计划...");
}
}
复制
此时如果要找产品改需求,就可以如下所示,先找到产品,然后增加功能,最后进行需求变更。
public class Test {
public static void main(String[] args) {
Group productManagerGroup = new ProductManagerGroup();
productManagerGroup.find();
productManagerGroup.add();
productManagerGroup.plan();
}
}
复制
找到需求组...
客户要求增加一项需求...
客户要求需求变更计划...
复制
如果需要找开发人员增加功能,那么同样也是先找到开发,然后增加功能,最后需求变更。
public class Test {
public static void main(String[] args) {
Group codeGroup = new CodeGroup();
codeGroup.find();
codeGroup.add();
codeGroup.plan();
}
}
复制
找到开发组...
客户要求增加一项需求...
客户要求需求变更计划...
复制
现在如果又要找UI更改图,是不是有需要先找到UI组,然后进行对应的操作,可是这样需求一直变来变去的,如果说找的是产品经理改了对应需求,而开发人员不知道啊,那么是不是可能最后实际的效果和客户要的不一致,因为产品没给开发同步。
而且对于客户来说我每次改需求难道所有的组都要通知吗?能不能给我来一个对接的人,我的需求改动也就是命令,只是告诉和我同步的人,然后同步的人告诉所有的开发人员。如果中间加了一个中间人这样也让客户和对应的开发人员做了解耦。
基于开发人员以及产品、美工的要求,我们加一个中间人,不然客户永远在随便单独叫人去改,改了也不给大家同步。
Command就是命令,对于客户提出的命令总要有人执行吧,所以在Command中引用了产品组、美工组以及代码组,毕竟命令来了要知道谁去做,而execute就是做事情的抽象,至于谁做,怎么做是子类应该决定的事情
public abstract class Command {
//把三个组都定义好,子类可以直接使用
//产品组
protected ProductManagerGroup pmg = new ProductManagerGroup();
//美工组
protected UiGroup ug = new UiGroup();
//代码组;
protected CodeGroup cg = new CodeGroup();
//只要一个方法,你要我做什么事情
public abstract void execute();
}
复制
Invoker就是中间人,客户只需要给中间人说我要改什么东西,至于究竟改谁改,都是中间人来决定,如果需要产品的原型图、ui的设计图、前端后端的代码都改动,那也是中间人来决定。
public class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
//执行客户的命令
public void action(){
this.command.execute();
}
}
复制
而对于AddRequirementCommand、ChangeRequirementCommand以及DeleteRequirementCommand都是一个命令,对需求改动的命令,至于让谁做是他们来决定的,我可以让产品、美工、开发都改动,也可以只让其中一个组做改动。现在如果要改动一个需求是不是可以通知到对应的组了,同时调用者和开发者做到了解耦。
public class AddRequirementCommand extends Command{
@Override
public void execute() {
super.pmg.find();
super.pmg.add();
super.pmg.plan();
}
}
复制
public class ChangeRequirementCommand extends Command{
@Override
public void execute() {
super.pmg.find();
super.pmg.change();
super.pmg.plan();
}
}
复制
public class DeleteRequirementCommand extends Command{
@Override
public void execute() {
super.pmg.find();
super.pmg.delete();
super.pmg.plan();
}
}
复制
现在对于客户来说只需要去找中间人,不在需要去一个一个的去找是那个组做,同时还避免了可能涉及到通知不到的组。
public class Test {
public static void main(String[] args) {
Invoker invoker = new Invoker(new AddRequirementCommand());
invoker.action();
}
}
复制
找到需求组...
客户要求增加一项需求...
客户要求需求变更计划...
复制
命令模式中的角色
Receiver角色:这个就是干活的角色,命令传递到这里是应该被执行的,具体到上面我们的例子中就是 Group 的三个实现类;
Command角色:就是命令,需要我执行的所有命令都这里声明;例子中就是对应的AddRequirementCommand、ChangeRequirementCommand以及DeleteRequirementCommand。
Invoker角色:调用者,接收到命令,并执行命令,例子中就是Invker类。
参考文献《设计模式之禅》
代码获取地址:https://gitee.com/bughong/design-pattern