设计模式学习笔记之命令模式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式学习笔记之命令模式相关的知识,希望对你有一定的参考价值。

命令模式
    将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
    说明:
    1、命令模式将发出请求的对象和执行请求的对象解耦;
    2、在被解耦的两者之间是通过命令对象进行沟通的。命令对象封装了接受者和一个或一组动作;
    3、调用者通过调用命令对象的execute()发出请求,这会使得接受者的动作被调用;
    4、调用者可以接受命令当做参数,甚至在运行时动态地进行;
    5、命令可以支持撤销,做法事实现一个undo()方法来回到exexcute()被执行前的状态;
    6、命令模式也可以用来实现日志和事物系统;
 技术分享
    优点:
    1、降低对象之间的耦合度;
    2、新的命令可以很容易地加入到系统中;
    3、可以比较容易地设计一个组合命令;
    4、调用同一方法实现不同的功能。
 
    缺点:
    使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。
 
    场景:
    1、系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互;
    2、系统需要在不同的时间指定请求、将请求排队和执行请求;
    3、系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作;
    4、系统需要将一组操作组合在一起,即支持宏命令;
 
技术分享
    例子:
    录音机有播音(Play)、倒带(Rewind)和停止(Stop)功能,录音机的键盘便是请求者(Invoker)角色;Leslie是客户端角色,而录音机便是接收者角色。Command类扮演抽象命令角色,而PlayCommand、StopCommand和RewindCommand便是具体命令类。Leslie不需要知道播音(play)、倒带(rewind)和停止(stop)功能是怎么具体执行的,这些命令执行的细节全都由键盘(Keypad)具体实施。Leslie只需要在键盘上按下相应的键便可以了。
/**
 * 命令接口。
 * 所有的命令对象需要实现该接口。
 * */
public interface Commond {
 
    public void execute();
 
}
/**
 * 录音机--命令接受者
 * */
public class AudioPlayer {
 
    public void play() {
        System.out.println("播放......");
    }
 
    public void stop() {
        System.out.println("暂停......");
    }
 
    public void rewind() {
        System.out.println("倒带......");
    }
}
 
/**
 * 录音机播放命令
 * 具体命令角色类
 * */
public class PlayCommond implements Commond{
 
    AudioPlayer player;
 
    public PlayCommond(AudioPlayer player) {
        this.player = player;
    }
 
    // 调用接收对象(录音机)的 play() 方法
    public void execute() {
        player.play();
    }
 
}
/**
 * 录音机倒带命令
 * 具体命令角色类
 * */
public class RewindCommond implements Commond{
 
    AudioPlayer player;
 
    public RewindCommond(AudioPlayer player) {
        this.player = player;
    }
 
    // 调用接收对象(录音机)的 rewind() 方法
    public void execute() {
        player.rewind();
    }
 
}
/**
 * 录音机暂停命令
 * 具体命令角色类
 * */
public class StopCommond implements Commond{
 
    AudioPlayer player;
 
    public StopCommond(AudioPlayer player) {
        this.player = player;
    }
 
    // 调用接收对象(录音机)的 stop() 方法
    public void execute() {
        player.stop();
    }
 
}
/**
 * 键盘类
 * 请求者角色
 * */
public class Keypad {
 
    private Commond play;
    private Commond stop;
    private Commond rewind;
 
    public void setPlayCommond(Commond play) {
        this.play = play;
    }
 
    public void setStopCommond(Commond stop) {
        this.stop = stop;
    }
 
    public void setRewindCommond(Commond rewind) {
        this.rewind = rewind;
    }
 
    // 执行播放方法
    public void play() {
        play.execute();
    }
 
    // 执行暂停方法
    public void stop() {
        stop.execute();
    }
 
    // 执行倒带方法
    public void rewind() {
        rewind.execute();
    }
}
/**
 * 具体人--莱斯利
 * 客户端角色
 * */
public class Leslie {
 
    public static void main(String[] args) {
 
        // 创建接受者对象,即收音机对象
        AudioPlayer player = new AudioPlayer();
        // 创建命令者对象
        Commond play = new PlayCommond(player);
        Commond stop = new StopCommond(player);
        Commond rewind = new RewindCommond(player);
        // 创建请求者对象,即键盘对象
        Keypad keypad = new Keypad();
        keypad.setPlayCommond(play);
        keypad.setStopCommond(stop);
        keypad.setRewindCommond(rewind);
 
        // 播放
        keypad.play();
        // 暂停
        keypad.stop();
        // 倒带
        keypad.rewind();
    }
}
    宏命令
    所谓宏命令简单点说就是包含多个命令的命令,是一个命令的组合。
    设想Leslie 的录音机有一个记录功能,可以把一个一个的命令记录下来,再在任何需要的时候重新把这些记录下来的命令一次性执行,这就是所谓的宏命令集功能。因此,Leslie 的录音机系统现在有四个键,分别为播音、倒带、停止和宏命令功能。此时系统的设计与前面的设计相比有所增强,主要体现在Julia类现在有了一个新方法,用以操作宏命令键。
/**
 * 定义宏命令接口
 * */
public interface MacroCommand extends Command{
 
    /**
     * 宏命令存储的管理方法
     * 可以添加一个成员命令
     */
    public void add(Command cmd);
 
    /**
     * 宏命令存储的管理方法
     * 可以删除一个成员命令
     */
    public void remove(Command cmd);
 
}
/**
 * 具体的宏命令,对存储的若干命令进行操作
 * */
public class MacroAudioCommand implements MacroCommand{
 
    // 宏命令集合
    private List<Command> cmdList = new ArrayList<Command>();
 
    // 一次性执行宏命令集合中的各命令
    public void execute() {
        System.out.println("-------自动回放保存的命令-------");
        for(Command cmd : cmdList)  {
            cmd.execute();
        }
        System.out.println("------------回放完毕------------");
    }
 
    public void add(Command cmd) {
        cmdList.add(cmd);
    }
 
    public void remove(Command cmd) {
        cmdList.remove(cmd);
    }
 
}
/**
 * 具体人--莱斯利
 * 客户端角色
 * */
public class Leslie {
 
    public static void main(String[] args) {
 
        // 创建接受者对象,即收音机对象
        AudioPlayer player = new AudioPlayer();
        // 创建命令者对象
        Command play = new PlayCommond(player);
        Command stop = new StopCommond(player);
        Command rewind = new RewindCommond(player);
 
        MacroCommand macro = new MacroAudioCommand();
        macro.add(play);
        macro.add(rewind);
        macro.add(stop);
        macro.execute();
    }
}
参考资料:《Head First 设计模式》

以上是关于设计模式学习笔记之命令模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式:学习笔记——命令者式

命令模式——HeadFirst设计模式学习笔记

Linux学习笔记之grep命令及sed 命令相关选项

设计模式学习笔记--命令模式

设计模式学习笔记(一:命令模式)

设计模式之命令模式学习理解