命令模式

命令模式的主要作用是将调用者与接收者进行解耦;将一个方法的调用封装成一个命令对象,因此调用者就无需了解内部的执行过程;而且当需要执行新的请求时,无需改变现有代码,只需要给调用者传递一个命令对象就可;

组成及关系图如下:

简单demo

  • client 客户端:关联invoker编译期就决定,依赖commond运行期才能决定
public class Client {
    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        Commond commond = new ConcreteCommond(receiver);
        Invoker invoker = new Invoker();
        invoker.setCommond(commond);
        invoker.action();
    }
}
复制代码
  • invoker
    调用者与common为组合关系
public class Invoker {
    private Commond commond;

    public void setCommond(Commond commond) {
        this.commond = commond;
    }
    public void action() {
        commond.excute();
    }
}
复制代码
  • command 命令的抽象,是一个接口,约定了excute方法
public interface Commond {
    void excute();
}
复制代码
  • concreteCommond 具体的命令 与接收者为关联关系,编译期就决定
public class ConcreteCommond implements Commond{
    private Receiver receiver;

    public ConcreteCommond(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void excute() {
        receiver.doSomething();
    }
}
复制代码
  • receiver 接收者,也是命令的具体执行者。
public class Receiver {
    public void doSomething() {
        System.out.println("receiver do something....");
    }
}
复制代码

由以上简单代码实例就可以看出,调用者与执行者没有直接关联,需要执行其他命令时,只需要新建一个命令将其赋予invoker就可以了,但是这样做也会产生一些缺点,系统中可能会出现许多命令类

单步undo操作

现在先写一个简单的能进行单步撤销的demo,模仿的记事本

receiver

public class Note {
    //输出文本内容
    public void write (String content) {
        System.out.println(content);
    }
}
复制代码

command

public interface Commond {
    //写入字符
    void excute(String content);

    //撤销
    void undo();
}
复制代码

concreteCommand

public class WriteCommond implements  Commond {
    private Note note;
    private String commondContent = "";  //当前文本的内容
    private int length = 0;   //保存一次操作写入的字符长度
    public WriteCommond(Note note) {
        this.note = note;
    }


    @Override
    public void excute(String content) {
        commondContent += content;
        note.write("现在              "+commondContent);
        length = content.length();
    }

    @Override
    public void undo() {
        //把最近一次输入长度的字符穿丢弃
        commondContent = commondContent.substring(0,commondContent.length()-length);
        note.write("撤销:           "+commondContent);
    }
}
复制代码

invoker

public class Invoker {
    private Commond commond;

    public void setCommond(Commond commond) {
        this.commond = commond;
    }
    public void write(String s) {
        commond.excute(s);
    }

    public void undo() {
        commond.undo();
    }
}
复制代码

client

public class Client {
    public static void main(String[] args) {
        Note note = new Note();
        Commond commond = new WriteCommond(note);
        Invoker invoker = new Invoker();
        invoker.setCommond(commond);
        invoker.write("aaaa");  //第一次写入aaaaa
        invoker.write("sss"); //再次写入sss,文本内容就变为aaaasss
        invoker.undo();   //撤销就变回aaaaa
    }
}
复制代码

执行结果如下:

多步undo、redo

receiver

public class Note {
    public void write (String content) {
        System.out.println(content);
    }
}
复制代码

command

public interface Commond {
    //执行
    void excute(String content);
    //撤销
    void undo();
    //取消撤销
    void redo();
}
复制代码

concreteCommand

public class WriteCommond implements Commond {
    private Note note;
    private String commondContent = "";  //当前文本的内容
    private Stack<Integer> lengths = new Stack<>();//保存每次操作写入的字符长度,用于撤销
    private Stack<String> Strings = new Stack<>(); //每次撤销掉的字符串,用于取消撤销
    public WriteCommond(Note note) {
        this.note = note;
    }


    @Override
    public void excute(String content) {
        commondContent += content;
        note.write("现在              "+commondContent);
        lengths.push(content.length());
        if (!Strings.empty()) {
            Strings.removeAllElements();   //执行了写操作,跟新至最新,清空取消撤销的内容
        }
    }

    @Override
    public void undo() {
        if (lengths.empty()) {
            System.out.println("无法继续ctrl+z");
            return;
        }
        Integer length = lengths.pop(); //撤销长度
        int contentcLength = commondContent.length(); //内容长度
        String redoString = commondContent.substring(contentcLength-length,contentcLength);//撤销掉的字符串
        Strings.push(redoString);  //撤销的内容 放入redo容器

        //把最近一次输入长度的字符穿丢弃,及执行撤销
        String outContent = commondContent.substring(0, contentcLength -length);
        commondContent = outContent;
        note.write("撤销:           "+outContent);

    }

    @Override
    public void redo() {
        if (Strings.empty()) {
            System.out.println("已是最新状态,无法继续ctrl+y");
            return ;
        }
        String redoString = Strings.pop();
        commondContent += redoString;
        note.write("取消撤销:           "+commondContent);
        lengths.push(redoString.length());
    }
}
复制代码

invoker

public class Invoker {
    private Commond commond;

    public void setCommond(Commond commond) {
        this.commond = commond;
    }
    public void write(String s) {
        commond.excute(s);
    }

    public void undo() {
        commond.undo();
    }
    public void redo() {
        commond.redo();
    }
}
复制代码

client

public class Client {
    public static void main(String[] args) {
        Note note = new Note();
        Commond commond = new WriteCommond(note);
        Invoker invoker = new Invoker();
        invoker.setCommond(commond);

        invoker.undo();
        invoker.write("aaaa");  //第一次写入aaaaa
        invoker.write("sss"); //再次写入sss,文本内容就变为aaaasss
        invoker.undo();   //撤销就变回aaaaa
        invoker.undo();   //再撤销就变回""
        invoker.redo();   //取消撤销就变回aaaaa
        invoker.undo();   //撤销又变回" "
    }
}
复制代码

执行结果

其实主要就是在concreteCommond中记录一些状态、标志用于执行相关的redo、undo

转载于:https://juejin.im/post/5bfe7b3c51882546150ab4cf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值