美文网首页
命令模式

命令模式

作者: 缓慢移动的蜗牛 | 来源:发表于2019-11-25 20:37 被阅读0次

    命令模式的定义

    定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

    命令模式的通用类图


    命令模式通用类图.png

    角色说明

    • Receiver接受者角色
      该角色就是具体干活的角色,命令传递到这里是应该被执行的

    • Command命令角色
      需要执行的所有命令都在这里声明。

    • Invoker调用者角色
      接收到命令,并执行命令。

    命令模式比较简单,但是在项目中非常频繁地使用,因为它封装性非常好,把请求放(Invoker)和执行放(Receiver)分开了,扩展性也有很好的保障,通用代码如下:

    通用代码

    Receiver类

    public abstract class Receiver {
         //抽象接收者,定义每个接收者都必须完成的业务
         public abstract void doSomething();
    }
    

    具体的Receiver类

    public class ConcreteReciver1 extends Receiver{
         //每个接收者都必须处理一定的业务逻辑
         public void doSomething(){
         }
    }
    
    public class ConcreteReciver2 extends Receiver{
         //每个接收者都必须处理一定的业务逻辑
         public void doSomething(){
         }
    }
    

    抽象的Command类

    public abstract class Command {
        //定义一个子类的全局共享变量
        protected final Receiver receiver;
        //实现类必须定义一个接受者
        public Command(Receiver receiver){
            this.receiver=receiver;
        }
         //每个命令类都必须有一个执行命令的方法
         public abstract void execute();
    }
    

    具体的Command类

    public class ConcreteCommand1 extends Command {
        //声明自己默认的接收者
        public ConcreteCommand1(){
            super(new ConcreteReceiver1());
        }
         //构造函数传递接收者
         public ConcreteCommand1(Receiver _receiver){
                 this.receiver = _receiver;
         }
         //必须实现一个命令
         public void execute() {
                 //业务处理
                 this.receiver.doSomething();
         }
    }
    
    public class ConcreteCommand2 extends Command {
         //声明自己默认的接收者
        public ConcreteCommand2(){
            super(new ConcreteReceiver2());
        }
         //构造函数传递接收者
         public ConcreteCommand2(Receiver _receiver){
                 this.receiver = _receiver;
         }
         //必须实现一个命令
         public void execute() {
                 //业务处理
                 this.receiver.doSomething();
         }
    }
    

    调用者Invoker类

    public class Invoker {
         private Command command;
         //受气包,接受命令
         public void setCommand(Command _command){
                 this.command = _command;
         }
         //执行命令
         public void action(){
                 this.command.execute();
         }
    }
    

    场景类

    public class Client {
         public static void main(String[] args) {
                 //首先声明调用者Invoker
                 Invoker invoker = new Invoker();
                 //定义接收者
                 //Receiver receiver = new ConcreteReciver1();
                 //定义一个发送给接收者的命令
                 Command command = new ConcreteCommand1();
                 //把命令交给调用者去执行
                 invoker.setCommand(command);
                 invoker.action();
         }
    }
    

    示例

    模拟项目开发的场景,项目组分为:需求组(Requirement Group,RG)、美工组(PageGroup,PG)、代码组(CodeGroup,CG)。依据甲方的要求,各小组修改相关的内容。

    示例类图:


    命令模式示例类图.png

    抽象组

    public abstract class Group {
         //甲乙双方分开办公,如果你要和某个组讨论,你首先要找到这个组
         public abstract void find();
         //被要求增加功能
         public abstract void add();
         //被要求删除功能
         public abstract void delete();
         //被要求修改功能
         public abstract void change();
         //被要求给出所有的变更计划
         public abstract void plan();
    }
    

    需求组

    public class RequirementGroup extends Group {
         //客户要求需求组过去和他们谈
         public void find() {
                 System.out.println("找到需求组...");
         }
         //客户要求增加一项需求
         public void add() {
                 System.out.println("客户要求增加一项需求...");
         }
         //客户要求修改一项需求
         public void change() {
                 System.out.println("客户要求修改一项需求...");
         }
         //客户要求删除一项需求
         public void delete() {
                 System.out.println("客户要求删除一项需求...");
         }
         //客户要求给出变更计划
         public void plan() {
                 System.out.println("客户要求需求变更计划...");
         }
    }
    

    美工组

    public class PageGroup extends Group {
         //首先这个美工组应该能找到吧,要不你跟谁谈?
         public void find() {
                 System.out.println("找到美工组...");
         }
         //美工被要求增加一个页面
         public void add() {
                 System.out.println("客户要求增加一个页面...");
         }
         //客户要求对现有界面做修改
         public void change() {
                 System.out.println("客户要求修改一个页面...");
         }
         //甲方是老大,要求删除一些页面
         public void delete() {
                 System.out.println("客户要求删除一个页面...");
         }
         //所有的增、删、改都要给出计划
         public void plan() {
                 System.out.println("客户要求页面变更计划...");
         }
    }
    

    代码组

    public class CodeGroup extends Group {
         //客户要求代码组过去和他们谈
         public void find() {
                 System.out.println("找到代码组...");
         }
         //客户要求增加一项功能
         public void add() {
                 System.out.println("客户要求增加一项功能...");
         }
         //客户要求修改一项功能
         public void change() {
                 System.out.println("客户要求修改一项功能...");
         }
         //客户要求删除一项功能
         public void delete() {
                 System.out.println("客户要求删除一项功能...");
         }
         //客户要求给出变更计划
         public void plan() {
                 System.out.println("客户要求代码变更计划...");
         }
    }
    

    抽象命令类

    public abstract class Command {
         //把三个组都定义好,子类可以直接使用
         protected RequirementGroup rg = new RequirementGroup();  //需求组
         protected PageGroup pg = new PageGroup();  //美工组
         protected CodeGroup cg = new CodeGroup();  //代码组
         //只有一个方法,你要我做什么事情
         public abstract void execute();
    }
    

    增加需求的命令

    public class AddRequirementCommand extends Command {
         //执行增加一项需求的命令
         public void execute() {
                 //找到需求组
                 super.rg.find();
                 //增加一份需求
                 super.rg.add();
                 //给出计划
                 super.rg.plan();
         }
    }
    

    删除页面的命令

    public class DeletePageCommand extends Command {
         //执行删除一个页面的命令
         public void execute() {
                 //找到页面组
                 super.pg.find();
                 //删除一个页面
                 super.rg.delete();
                 //给出计划
                 super.rg.plan();
         }
    }
    

    负责人

    public class Invoker {
         //什么命令
         private Command command;
         //客户发出命令
         public void setCommand(Command command){
                 this.command = command;
         }
         //执行客户的命令
         public void action(){
                 this.command.execute();
         }
    }
    
    

    场景:增加一项需求

    public class Client {
         public static void main(String[] args) {
                 //定义我们的接头人
                 Invoker xiaoSan = new Invoker();  //接头人就是小三
                 //客户要求增加一项需求
                 System.out.println("------------客户要求增加一项需求---------------");
                 //客户给我们下命令来
                 Command command = new AddRequirementCommand();
                 //接头人接收到命令
                 xiaoSan.setCommand(command);
                 //接头人执行命令
                 xiaoSan.action();
         }
    }
    

    场景:删除一个页面

    public class Client {
         public static void main(String[] args) {
                 //定义我们的接头人
                 Invoker xiaoSan = new Invoker();  //接头人就是小三
                 //客户要求增加一项需求
                 System.out.println("------------客户要求删除一个页面---------------");
                 //客户给我们下命令来
                 //Command command = new AddRequirementCommand();
                 Command command = new DeletePageCommand();
                 //接头人接收到命令
                 xiaoSan.setCommand(command);
                 //接头人执行命令
                 xiaoSan.action();
         }
    }
    

    命令者模式的应用

    优点

    • 类间解耦
      调用者角色与接受者角色之间没有任何依赖,调用者实现功能时只需要调用Comand抽象类的execute方法就可以,不需要了解到底是哪个接受者执行。

    • 可扩展性
      Command的子类可以非常容易地扩展,而调用者Invoker和高层的模块Client不产生严重的代码耦合。

    • 命令模式结合其他模式会更优秀
      命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少Command子类的膨胀问题。

    缺点

    请看Comand的子类,如果有N个命令,问题就出来了,Command的子类就可不是几个,而是N个,这个子类膨胀得非常大。

    相关文章

      网友评论

          本文标题:命令模式

          本文链接:https://www.haomeiwen.com/subject/gwtswctx.html