• 命令(Command)模式


      命令模式又称为行动(Action)模式或者交易(Transaction)模式。

      命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销或恢复功能。

      命令模式是对命令的封装。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。

    1.  结构

    涉及的角色如下:

    客户角色:创建了一个具体命令(ConcreteCommand)对象并确定其接收者。

    命令(Command)角色:声明了一个给所有具体命令类的抽象接口。

    具体命令(ConcreteCommand)角色:定义一个接收者和行为之间的弱耦合;实现execute方法,负责调用接收者的相应操作。execute()方法通常叫做执行方法。

    请求者(Invoker)角色:负责调用命令对象执行请求,相关的方法叫做行动方法。

    接收者(Receiver)角色:负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做行动方法。

    源码如下:

    接收者:

    package command;
    
    public class Receiver {
    
        /**
         * 真正执行命令相应的操作
         */
        public void action() {
            System.out.println("接收者处理请求");
        }
    }

    抽象命令:

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

    具体命令:

    package command;
    
    public class ConcreteCommand implements Command {
    
        // 接收者
        private Receiver receiver;
    
        public ConcreteCommand(Receiver receiver) {
            super();
            this.receiver = receiver;
        }
    
        public Receiver getReceiver() {
            return receiver;
        }
    
        public void setReceiver(Receiver receiver) {
            this.receiver = receiver;
        }
    
        @Override
        public void execute() {
            // 让接收者执行功能
            receiver.action();
        }
    
    }

    请求者:

    package command;
    
    public class Invoker {
    
        // 命令
        private Command command;
    
        public Invoker(Command command) {
            super();
            this.command = command;
        }
    
        public void action() {
            command.execute();
        }
    
        public Command getCommand() {
            return command;
        }
    
        public void setCommand(Command command) {
            this.command = command;
        }
    
    }

    客户端代码如下

    package command;
    
    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();
        }
    }

    结果:

    接收者处理请求

    2.   AudioPlayer系统

      小女孩茱丽(Julia)有一个盒式录音机,此录音机有播音(Play)、倒带(Rewind)和停止(Stop)功能,录音机的键盘便是请求者(Invoker)角色;茱丽(Julia)是客户端角色,而录音机便是接收者角色。Command类扮演抽象命令角色,而PlayCommand、StopCommand和RewindCommand便是具体命令类。茱丽(Julia)不需要知道播音(play)、倒带(rewind)和停止(stop)功能是怎么具体执行的,这些命令执行的细节全都由键盘(Keypad)具体实施。茱丽(Julia)只需要在键盘上按下相应的键便可以了。

      录音机是典型的命令模式。录音机按键把客户端与录音机的操作细节分割开来。

    系统类图如下:

     

    角色如下:

    客户端角色:在这里由Julia扮演

    请求者(Invoekr)角色:在这里由键盘类(Keypad)扮演 

    抽象命令(Command)就是: 给出同一的接口

    具体命令角色:PlayCommand、RewindCommand、StopCommand三个类扮演

    命令接收者(Receiver):在这里由录音机(AudioPlayer)扮演

    源码如下:

    命令类:

    package command;
    
    public interface Command {
    
        /**
         * 执行方法
         */
        void execute();
    
    }
    package command;
    
    /**
     * 播放命令
     * 
     * @author Administrator
     *
     */
    public class PlayCommand implements Command {
    
        // 命令接收者
        private AudioPlayer audioPlayer;
    
        public PlayCommand(AudioPlayer audioPlayer) {
            super();
            this.audioPlayer = audioPlayer;
        }
    
        @Override
        public void execute() {
            audioPlayer.play();
        }
    
    }
    package command;
    
    /**
     * 倒带命令
     * 
     * @author Administrator
     *
     */
    public class RewindCommand implements Command {
    
        // 命令接收者
        private AudioPlayer audioPlayer;
    
        public RewindCommand(AudioPlayer audioPlayer) {
            super();
            this.audioPlayer = audioPlayer;
        }
    
        @Override
        public void execute() {
            audioPlayer.rewind();
        }
    
    }
    package command;
    
    /**
     * 停止命令
     * 
     * @author Administrator
     *
     */
    public class StopCommand implements Command {
    
        // 命令接收者
        private AudioPlayer audioPlayer;
    
        public StopCommand(AudioPlayer audioPlayer) {
            super();
            this.audioPlayer = audioPlayer;
        }
    
        @Override
        public void execute() {
            audioPlayer.stop();
        }
    
    }

    命令接收者:

    package command;
    
    /**
     * 命令接收者 (录音机)
     * 
     * @author Administrator
     *
     */
    public class AudioPlayer {
    
        public void play() {
            System.out.println("play ...");
        }
    
        public void rewind() {
            System.out.println("rewind ...");
        }
    
        public void stop() {
            System.out.println("stop ...");
        }
    }

    命令请求者:

    package command;
    
    /**
     * 请求角色(键盘扮演)
     * 
     * @author Administrator
     *
     */
    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();
        }
    }

    客户端:

    package command;
    
    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();
        }
    }

    结果:

    play ...
    rewind ...
    stop ...
    play ...
    stop ...

    3. 增加宏命令

      所谓宏命令简单点说就是包含多个命令的命令,是一个命令的组合。

      设想茱丽的录音机有一个记录功能,可以把一个一个的命令记录下来,再在任何需要的时候重新把这些记录下来的命令一次性执行,这就是所谓的宏命令集功能。因此,茱丽的录音机系统现在有四个键,分别为播音、倒带、停止和宏命令功能。此时系统的设计与前面的设计相比有所增强,主要体现在Julia类现在有了一个新方法,用以操作宏命令键。

    类图如下: 增加了MacroCommand接口,MacroAudioCommand实现新加的接口

    代码如下:

    package command;
    
    public interface MacroCommand extends Command {
    
        /**
         * 可以添加一个成员命令
         */
        public void add(Command cmd);
    
        /**
         * 删除一个成员命令
         */
        public void remove(Command cmd);
    }
    package command;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MacroAudioCommand implements MacroCommand {
    
        private List<Command> commandList = new ArrayList<Command>();
    
        @Override
        public void execute() {
            for (Command command : commandList) {
                command.execute();
            }
        }
    
        @Override
        public void add(Command cmd) {
            commandList.add(cmd);
        }
    
        @Override
        public void remove(Command cmd) {
            commandList.remove(cmd);
        }
    
    }

    客户端类:

    package command;
    
    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();
        }
    }

    结果:

    play ...
    rewind ...
    stop ...

    补充:如果想实现撤销和重做还需要记录命令的状态。如果是提供一层的undo和redo,那么系统只需要存储最后被执行的那个命令对象。如果需要支持多层的undo和redo,那么系统就需要存储曾经被执行过的命令的清单,清单能允许的最大的长度便是系统所支持的undo和redo的层数。

    总结:

    意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。

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

    何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。

    如何解决:通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。

    关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口

    应用实例:struts 1 中的 action 核心控制器 ActionServlet 只有一个,相当于 Invoker,而模型层的类会随着不同的应用有不同的模型类,相当于具体的 Command。

    优点: 1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。

    缺点:使用命令模式可能会导致某些系统有过多的具体命令类。

    使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。

    注意事项:系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作,也可以考虑使用命令模式。

  • 相关阅读:
    将PHP文件生成静态文件源码
    Entity Framework Code First 学习日记(6)一对多关系
    Entity Framework Code First 学习日记(5)
    Entity Framework Code First 学习日记(3)
    Entity Framework Code First 学习日记(7)多对多关系
    Entity Framework Code First学习日记(2)
    Entity Framework Code First 学习日记(8)一对一关系
    Entity Framework Code First 学习日记(9)映射继承关系
    Entity Framework Code First 学习日记(10)兼容遗留数据库
    Entity Framework Code First 学习日记(4)
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/11490155.html
Copyright © 2020-2023  润新知