设计模式解密(11)- 命令模式

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

◆ 前言:命令模式内容比较多,这里做了拆分

命令模式基础篇 :http://www.cnblogs.com/JsonShare/p/7202133.html

命令模式扩展篇 - 宏命令:http://www.cnblogs.com/JsonShare/p/7206395.html

命令模式扩展篇 - 撤销命令:http://www.cnblogs.com/JsonShare/p/7206513.html

命令模式扩展篇 - 命令队列:http://www.cnblogs.com/JsonShare/p/7206607.html

命令模式扩展篇 - 请求日志:http://www.cnblogs.com/JsonShare/p/7206665.html

1、简介

定义:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作;

主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种紧耦合的设计就不太合适;

英文:Command

类型:行为型模式

2、类图及组成

(引)类图:

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

组成:
  ● Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。

  ● ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。

  ● Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。

  ● Receiver(接收者):接收者请求与执行相关的操作,它具体实现对请求的业务处理。

  ● Client(客户端角色类):最终的客户端调用类。

代码结构:

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

抽象命令角色类public interface Command {    /**
     * 执行方法     */
    void execute();
}

具体命令角色类public class ConcreteCommand implements Command {    //持有相应的接收者对象
    private Receiver receiver = null;    /**
     * 构造方法     */
    public ConcreteCommand(Receiver receiver){        this.receiver = receiver;
    }
    @Override    public void execute() {        //通常会转调接收者对象的相应方法,让接收者来真正执行功能        receiver.action();
    }
}

接收者角色类public class Receiver {    /**
     * 真正执行命令相应的操作     */
    public void action(){
        System.out.println("执行操作");
    }
}

请求者角色类public class Invoker {    /**
     * 持有命令对象     */
    private Command command = null;    /**
     * 构造方法     */
    public Invoker(Command command){        this.command = command;
    }    /**
     * 行动方法     */
    public void action(){
        command.execute();
    }
}

客户端角色类public class Client {    public static void main(String[] args) {        //创建接收者
        Receiver receiver = new Receiver();        //创建命令对象,设定它的接收者
        Command command = new ConcreteCommand(receiver);        //创建请求者,把命令对象设置进去
        Invoker invoker = new Invoker(command);        //执行方法        invoker.action();
    }
}

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

3、实例引入

下面以电视机的开、关命令为例,进行讲解:

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

package com.designpattern.Command;/**
 * 抽象命令角色类
 * @author Json*/public interface Command {     /**
     * 执行方法     */
    void execute();
}

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

package com.designpattern.Command;/**
 * 接收者角色类  -- 电视
 * @author Json*/public class TV {    /**
     * 打开方法     */
    public void on(){
        System.out.println("电视打开");
    }    /**
     * 关闭方法     */
    public void off(){
        System.out.println("电视关闭");
    }
}

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

package com.designpattern.Command;/**
 * 具体命令角色类  -- 电视打开命令
 * @author Json*/public class TVOnCommand implements Command {    private TV tv;    public TVOnCommand(TV tv){        this.tv = tv;
    }
    
    @Override    public void execute() {
        tv.on();
    }
}

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

package com.designpattern.Command;/**
 * 具体命令角色类  -- 电视关闭命令
 * @author Json*/public class TVOffCommand implements Command {    private TV tv;    public TVOffCommand(TV tv){        this.tv = tv;
    }
    
    @Override    public void execute() {
        tv.off();
    }
}

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

package com.designpattern.Command;/**
 * 请求者角色类  -- 遥控器Invoker
 * @author Json*/public class RemoteControl {    private Command onCommand,offCommand;    
    public RemoteControl(Command _on,Command _off){        this.onCommand = _on;        this.offCommand = _off;
    }    
    public void turnOn(){
        onCommand.execute();
    }    
    public void turnOff(){
        offCommand.execute();
    }
}

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

 测试:

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

package com.designpattern.Command;/**
 * 客户端角色类
 * @author Json*/public class Client {    public static void main(String[] args) {        //创建接收者
        TV receiver = new TV();        //创建命令对象,设定它的接收者
        Command on_command = new TVOnCommand(receiver);        //创建命令对象,设定它的接收者
        Command off_command = new TVOffCommand(receiver);        //命令控制对象Invoker,把命令对象通过构造方法设置进去 或者 增加set方法set进去是一样的(setCommand方法未写)
        RemoteControl invoker = new RemoteControl(on_command,off_command);        //执行方法  -- 打开电视        invoker.turnOn();        //执行方法 -- 关闭电视        invoker.turnOff();
    }
}

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

 结果:

电视打开
电视关闭

关于例子的补充说明:

虽然代码看似挺多,但其实命令模式的结构还是比较清晰的,总的来说命令模式的使用流程就是首先创建一个抽象命令,然后创建多个具体命令实现抽象命令接口,然后创建一个命令接受者角色,它包含各种的行为的具体实现,然后再有一个命令调用者角色,提供给客户端,用于接收客户端的参数;

4、命令模式的扩展

 由于篇幅太长,这里单独拆分出去了;

传送门:

  命令模式扩展篇 - 宏命令:http://www.cnblogs.com/JsonShare/p/7206395.html

  命令模式扩展篇 - 撤销命令:http://www.cnblogs.com/JsonShare/p/7206513.html

  命令模式扩展篇 - 命令队列:http://www.cnblogs.com/JsonShare/p/7206607.html

  命令模式扩展篇 - 请求日志:http://www.cnblogs.com/JsonShare/p/7206665.html

5、优缺点

优点:

  1、命令模式将行为调用者和各种行为分隔开,降低程序的耦合,便于程序扩展;

  2、命令模式将行为的具体实现封装起来,客户端无需关心行为的具体实现;

  3、命令模式可为多种行为提供统一的调用入口,便于程序对行为的管理和控制;

缺点:

  使用命令模式的话,不用管命令多简单,都需要写一个命令类来封装,使用命令模式可能会导致系统有过多的具体命令类;

     (上面的例子就可以看出,每个命令都要有一个具体的命令类);

6、应用场景

  1、希望将行为请求者和行为实现者解耦,不直接打交道;

  2、希望分离掉行为请求者一部分的责任,行为请求者只需要将命令发给调用者,不再主动的去让行为实现者产生行为,符合单一职责原则;

  3、希望可以控制执行的命令列表,方便记录,撤销/重做以及事务等功能;

  4、期待可以将请求排队,有序执行;

  5、希望可以将请求组合使用,即支持宏命令;

7、总结

  命令模式最大的好处就是实现了行为请求者与行为实现者的解耦;

  在实际场景中的使用:

      Struts2中action中的调用过程中存在命令模式;

      数据库中的事务机制的底层实现;

      命令的撤销和恢复:增加相应的撤销和恢复命令的方法(比如数据库中的事务回滚);

  例如:Java的Runnable就是命令模式的变形应用:

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

public class Test {    public static void main(String[] args) {        //范例
        Runnable runnable = () -> System.out.println("具体命令"); // Command cmd = ConcreteCommand
        Thread thread1 = new Thread(runnable); // 将 cmd 交给 Thread (Invoker)
        thread1.start(); // Invoker 调用 cmd 的执行方法    }
}

seo优化培训,网络推广培训,网络营销培训,SEM培训,网络优化,在线营销培训

 

 

PS:源码地址   https://github.com/JsonShare/DesignPattern/tree/master 

     

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力! 
如果标题被标记为转载,转载请注明原作者地址,详见引用 
版权声明,转载请注明出处:http://www.cnblogs.com/JsonShare

http://www.cnblogs.com/JsonShare/p/7202133.html