设计模式(十七)命令模式(行为型)

概述

命令模式(Command Pattern):将一个请求封装为一个对象,从而让咱们可用不一样的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操做。命令模式是一种对象行为型模式,其别名为动做(Action)模式或事务(Transaction)模式。java

在命令模式结构图中包含以下几个角色:编程

       ● Command(抽象命令类):抽象命令类通常是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,经过这些方法能够调用请求接收者的相关操做。设计模式

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

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

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

命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开。每个命令都是一个操做:请求的一方发出请求要求执行一个操做;接收的一方收到请求,并执行相应的操做。命令模式容许请求的一方和接收的一方独立开来,使得请求的一方没必要知道接收请求的一方的接口,更没必要知道请求如何被接收、操做是否被执行、什么时候被执行,以及是怎么被执行的。设计

命令模式的关键在于引入了抽象命令类,请求发送者针对抽象命令类编程,只有实现了抽象命令类的具体命令才与请求接收者相关联。在最简单的抽象命令类中只包含了一个抽象的execute()方法,每一个具体命令类将一个Receiver类型的对象做为一个实例变量进行存储,从而具体指定一个请求的接收者,不一样的具体命令类提供了execute()方法的不一样实现,并调用不一样接收者的请求处理方法。日志

典型的抽象命令类代码以下所示:code

abstract class Command {  
    public abstract void execute();  
}

对于请求发送者即调用者而言,将针对抽象命令类进行编程,能够经过构造注入或者设值注入的方式在运行时传入具体命令类对象并在业务方法中调用命令对象的execute()方法,其典型代码以下所示:对象

class Invoker {  
    private Command command;  
      
    //构造注入  
    public Invoker(Command command) {  
        this.command = command;  
    }  
      
    //设值注入  
    public void setCommand(Command command) {  
        this.command = command;  
    }  
      
    //业务方法,用于调用命令类的execute()方法  
    public void call() {  
        command.execute();  
    }  
}

具体命令类继承了抽象命令类,它与请求接收者相关联,实现了在抽象命令类中声明的execute()方法,并在实现时调用接收者的请求响应方法action(),其典型代码以下所示:

class ConcreteCommand extends Command {  
    private Receiver receiver; //维持一个对请求接收者对象的引用  
  
    public void execute() {  
        receiver.action(); //调用请求接收者的业务处理方法action()  
    }  
}

请求接收者Receiver类具体实现对请求的业务处理,它提供了action()方法,用于执行与请求相关的操做,其典型代码以下所示:

class Receiver {  
    public void action() {  
        //具体操做  
    }  
}

Demo

接收者角色,由录音机类扮演

public class AudioPlayer {
    
    public void play(){
        System.out.println("播放...");
    }
    
    public void rewind(){
        System.out.println("倒带...");
    }
    
    public void stop(){
        System.out.println("中止...");
    }
}

抽象命令角色类

public interface Command {
    /**
     * 执行方法
     */
    public void execute();
}

具体命令角色类

public class PlayCommand implements Command {

    private AudioPlayer myAudio;
    
    public PlayCommand(AudioPlayer audioPlayer){
        myAudio = audioPlayer;
    }
    /**
     * 执行方法
     */
    @Override
    public void execute() {
        myAudio.play();
    }
}

public class RewindCommand implements Command {

    private AudioPlayer myAudio;
    
    public RewindCommand(AudioPlayer audioPlayer){
        myAudio = audioPlayer;
    }
    @Override
    public void execute() {
        myAudio.rewind();
    }
}

public class StopCommand implements Command {
    private AudioPlayer myAudio;
    
    public StopCommand(AudioPlayer audioPlayer){
        myAudio = audioPlayer;
    }
    @Override
    public void execute() {
        myAudio.stop();
    }
}

请求者角色,由键盘类扮演

public class Keypad {
    private Command playCommand;
    private Command rewindCommand;
    private Command stopCommand;
    
    public void setPlayCommand(Command playCommand) {
        this.playCommand = playCommand;
    }
    public void setRewindCommand(Command rewindCommand) {
        this.rewindCommand = rewindCommand;
    }
    public void setStopCommand(Command stopCommand) {
        this.stopCommand = stopCommand;
    }
    /**
     * 执行播放方法
     */
    public void play(){
        playCommand.execute();
    }
    /**
     * 执行倒带方法
     */
    public void rewind(){
        rewindCommand.execute();
    }
    /**
     * 执行播放方法
     */
    public void stop(){
        stopCommand.execute();
    }
}

客户端角色,由茱丽小女孩扮演

public class Julia {
    public static void main(String[]args){
        //建立接收者对象
        AudioPlayer audioPlayer = new AudioPlayer();
        //建立命令对象
        Command playCommand = new PlayCommand(audioPlayer);
        Command rewindCommand = new RewindCommand(audioPlayer);
        Command stopCommand = new StopCommand(audioPlayer);
        //建立请求者对象
        Keypad keypad = new Keypad();
        keypad.setPlayCommand(playCommand);
        keypad.setRewindCommand(rewindCommand);
        keypad.setStopCommand(stopCommand);
        //测试
        keypad.play();
        keypad.rewind();
        keypad.stop();
        keypad.play();
        keypad.stop();
    }
}

播放...

倒带...

中止...

播放...

中止...

宏命令

宏命令(Macro Command)又称为组合命令,它是组合模式和命令模式联用的产物。宏命令是一个具体命令类,它拥有一个集合属性,在该集合中包含了对其余命令对象的引用。一般宏命令不直接与请求接收者交互,而是经过它的成员来调用接收者的方法。当调用宏命令的execute()方法时,将递归调用它所包含的每一个成员命令的execute()方法,一个宏命令的成员能够是简单命令,还能够继续是宏命令。执行一个宏命令将触发多个具体命令的执行,从而实现对命令的批处理,其结构如图所示:

宏命令Demo

系统须要一个表明宏命令的接口,以定义出具体宏命令所须要的接口。

public interface MacroCommand extends Command {
    /**
     * 宏命令汇集的管理方法
     * 能够添加一个成员命令
     */
    public void add(Command cmd);
    /**
     * 宏命令汇集的管理方法
     * 能够删除一个成员命令
     */
    public void remove(Command cmd);
}

具体的宏命令MacroAudioCommand类负责把个别的命令合成宏命令。

public class MacroAudioCommand implements MacroCommand {
    
    private List<Command> commandList = new ArrayList<Command>();
    /**
     * 宏命令汇集管理方法
     */
    @Override
    public void add(Command cmd) {
        commandList.add(cmd);
    }
    /**
     * 宏命令汇集管理方法
     */
    @Override
    public void remove(Command cmd) {
        commandList.remove(cmd);
    }
    /**
     * 执行方法
     */
    @Override
    public void execute() {
        for(Command cmd : commandList){
            cmd.execute();
        }
    }
}

客户端类Julia

public class Julia {
    
    public static void main(String[]args){
        //建立接收者对象
        AudioPlayer audioPlayer = new AudioPlayer();
        //建立命令对象
        Command playCommand = new PlayCommand(audioPlayer);
        Command rewindCommand = new RewindCommand(audioPlayer);
        Command stopCommand = new StopCommand(audioPlayer);
        
        MacroCommand marco = new MacroAudioCommand();
        
        marco.add(playCommand);
        marco.add(rewindCommand);
        marco.add(stopCommand);
        marco.execute();
    }
}

播放...

倒带...

中止...

总结

命令模式是一种使用频率很是高的设计模式,它能够将请求发送者与接收者解耦,请求发送者经过命令对象来间接引用请求接收者,使得系统具备更好的灵活性和可扩展性。在基于GUI的软件开发,不管是在电脑桌面应用仍是在移动应用中,命令模式都获得了普遍的应用。

  • 主要优势

命令模式的主要优势以下:

  1. 下降系统的耦合度。因为请求者与接收者之间不存在直接引用,所以请求者与接收者之间实现彻底解耦,相同的请求者能够对应不一样的接收者,一样,相同的接收者也能够供不一样的请求者使用,二者之间具备良好的独立性。
  2. 新的命令能够很容易地加入到系统中。因为增长新的具体命令类不会影响到其余类,所以增长新的具体命令类很容易,无须修改原有系统源代码,甚至客户类代码,知足“开闭原则”的要求。
  3. 能够比较容易地设计一个命令队列或宏命令(组合命令)
  4. 为请求的撤销(Undo)和恢复(Redo)操做提供了一种设计和实现方案

 

  • 主要缺点

命令模式的主要缺点以下:

使用命令模式可能会致使某些系统有过多的具体命令类。由于针对每个对请求接收者的调用操做都须要设计一个具体命令类,所以在某些系统中可能须要提供大量的具体命令类,这将影响命令模式的使用。

 

  • 适用场景

在如下状况下能够考虑使用命令模式:

  1. 系统须要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者无须知道接收者的存在,也无须知道接收者是谁,接收者也无须关心什么时候被调用。
  2. 系统须要在不一样的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调用者能够有不一样的生命期,换言之,最初的请求发出者可能已经不在了,而命令对象自己仍然是活动的,能够经过该命令对象去调用请求接收者,而无须关心请求调用者的存在性,能够经过请求日志文件等机制来具体实现。
  3. 系统须要支持命令的撤销(Undo)操做和恢复(Redo)操做。
  4. 系统须要将一组操做组合在一块儿造成宏命令。

我是天王盖地虎的分割线

相关文章
相关标签/搜索