一、场景
1、标题【泉源】
1.1 标题形貌
小明正在计划一个简朴的计数器应用,支持增长(Increment)和淘汰(Decrement)操纵,以及打消(Undo)和重做(Redo)操纵,请你利用备忘录模式帮他实现。
1.2 输入形貌
输入包罗多少行,每行包罗一个字符串,体现计数器应用的操纵,操纵包罗 “Increment”、“Decrement”、“Undo” 和 “Redo”。
1.3 输出形貌
对于每个 “Increment” 和 “Decrement” 操纵,输出当前计数器的值,计数器数值从0开始 对于每个 “Undo” 操纵,输出打消后的计数器值。 对于每个 “Redo” 操纵,输出重做后的计数器值。
1.4 输入示例
- Increment
- Increment
- Decrement
- Undo
- Redo
- Increment
复制代码 1.5 输出示例
2、明白需求
- 增长(Increment)和淘汰(Decrement)操纵比力好明白,不赘述了。
- 重点明白下:打消(Undo)和重做(Redo)操纵。
- 一样寻常编辑器,都支持Undo和Redo操纵。
- Undo操纵:由于操纵导致值发生厘革,比方,0酿成1。我们必要记下厘革的值,如许才方便用户回退。
- 很显着,应该用栈来纪录。比方:0 -> 1 -> 2 -> 3。 当前处于3,接下来Undo,应该从3酿成2。也就是把3从栈中弹出。
- Redo操纵:依然基于“0 -> 1 -> 2 -> 3”举行分析,当前处于3,用户Undo后,3酿成2,接下来,用户Redo了,也就是渴望2又变回3。
- 也就是,我们必要纪录Undo栈中弹出来的值。很显然,也是一个栈。
二、不接纳备忘录计划模式
1、代码
- public class Main {
- public static void main(String[] args) {
- Scanner scanner = new Scanner(System.in);
- int res = 0;
- // 栈
- Deque<Integer> undoStack = new ArrayDeque<>();
- undoStack.push(res);
- Deque<Integer> redoStack = new ArrayDeque<>();
- while (scanner.hasNextLine()) {
- String command = scanner.nextLine();
- res = runCommand(command, res, undoStack, redoStack);
- System.out.println(res);
- }
- }
- private static Integer runCommand(String command, Integer res, Deque<Integer> undoStack, Deque<Integer> redoStack) {
- if ("Increment".equals(command)) {
- res += 1;
- undoStack.push(res);
- return res;
- } else if ("Decrement".equals(command)) {
- res -= 1;
- undoStack.push(res);
- return res;
- } else if ("Undo".equals(command)) {
- if (undoStack.size() == 1) {
- // 相当于还没有做任何操作,用户就执行了Undo
- return undoStack.peek();
- } else if (undoStack.size() > 1) {
- Integer value = undoStack.pop();
- redoStack.push(value);
- return undoStack.peek();
- }
- } else if ("Redo".equals(command)) {
- if (!redoStack.isEmpty()) {
- Integer value = redoStack.pop();
- undoStack.push(value);
- return value;
- }
- }
- return res;
- }
- }
复制代码 2、标题
- Increment等操纵是客户端(main方法)的下令,客户端不应该看到undoStack、redoStack等数据。
- 上面的写法是典范的面向过程开发,我们必要利用面向对象开发。
- 很显然,我们必要计划一个Calculator。
- public class Calculator {
- private int value;
- public Calculator() {
- this.value = 0;
- }
- public Integer runCommand(String command) {
- return null;
- }
- }
- public class Main {
- public static void main(String[] args) {
- Scanner scanner = new Scanner(System.in);
- Calculator calculator = new Calculator();
- while (scanner.hasNextLine()) {
- String command = scanner.nextLine();
- Integer res = calculator.runCommand(command);
- System.out.println(res);
- }
- }
- }
复制代码
- 为了实现Undo、Redo,这个类的对象有一个特点,必要生存和规复对象之前的状态。
- 备忘录模式是一种举动计划模式, 答应在不袒露对象实现细节的情况下生存和规复对象之前的状态。[先有场景,后有计划模式]
3、错误的备忘录模式
- public class Calculator {
- private int value;
- private Deque<Integer> undoStack;
- private Deque<Integer> redoStack;
- public Calculator() {
- this.value = 0;
- this.undoStack = new ArrayDeque<>();
- undoStack.push(value);
- this.redoStack = new ArrayDeque<>();
- }
- public Integer runCommand(String command) {
- if ("Increment".equals(command)) {
- value += 1;
- undoStack.push(value);
- return value;
- } else if ("Decrement".equals(command)) {
- value -= 1;
- undoStack.push(value);
- return value;
- } else if ("Undo".equals(command)) {
- if (undoStack.size() == 1) {
- // 相当于还没有做任何操作,用户就执行了Undo
- return undoStack.peek();
- } else if (undoStack.size() > 1) {
- Integer v = undoStack.pop();
- redoStack.push(v);
- return undoStack.peek();
- }
- } else if ("Redo".equals(command)) {
- if (!redoStack.isEmpty()) {
- Integer v = redoStack.pop();
- undoStack.push(v);
- return v;
- }
- }
- return value;
- }
- }
复制代码
- Calculator这个类是违背单一职责的,按照备忘录模式的经典计划,应该具有3个脚色:
- Originator(原发器):状态持有者,而且可以哀求生存状态和规复状态。
- Memento(备忘录):负责生存状态和规复状态。
- Caretaker(负责人):负责管理备忘录。
三、接纳备忘录计划模式
1、代码
1.1 Originator(原发器)
- public class Counter {
- private int value;
- public Counter() {
- this.value = 0;
- }
- public int getValue() {
- return value;
- }
- public void increment() {
- this.value++;
- }
- public void decrement() {
- this.value--;
- }
- public Memento createMemento() {
- return new Memento(this.value);
- }
- public void restoreMemento(Memento memento) {
- this.value = memento.getValue();
- }
- }
复制代码 1.2 Memento(备忘录)
- public class Memento {
- private int value;
- public Memento(int value) {
- this.value = value;
- }
- public int getValue() {
- return value;
- }
- }
复制代码 1.3 Caretaker(负责人)
- public class Calculator {
- private Counter counter;
- private Deque<Memento> undoStack;
- private Deque<Memento> redoStack;
- public Calculator() {
- counter = new Counter();
- undoStack = new ArrayDeque<>();
- redoStack = new ArrayDeque<>();
- }
- public Integer runCommand(String command) {
- if (command.equals("Increment")) {
- counter.increment();
- undoStack.push(counter.createMemento());
- redoStack.clear(); // redoStack是专门用来记录undoStack弹出的状态的,undoStack放入新状态后,redoStack里面的状态就无效了
- } else if (command.equals("Decrement")) {
- counter.decrement();
- undoStack.push(counter.createMemento());
- redoStack.clear();
- } else if (command.equals("Undo")) {
- if (!undoStack.isEmpty()) {
- Memento memento = undoStack.pop();
- redoStack.push(memento);
- counter.restoreMemento(undoStack.peek());
- }
- } else if (command.equals("Redo")) {
- if (!redoStack.isEmpty()) {
- Memento memento = redoStack.pop();
- counter.restoreMemento(memento);
- undoStack.push(memento);
- }
- } else {
- throw new RuntimeException("Unknown command");
- }
- return counter.getValue();
- }
- }
复制代码 1.4 客户端
- public class Main {
- public static void main(String[] args) {
- Scanner scanner = new Scanner(System.in);
- Calculator calculator = new Calculator();
- while (scanner.hasNextLine()) {
- String command = scanner.nextLine();
- Integer res = calculator.runCommand(command);
- System.out.println(res);
- }
- }
- }
复制代码 2、思索
- 相比“3、错误的备忘录模式”,每个类的职责更单逐一些。但,Memento好贫苦啊。相当于把Counter的字段复制了一遍。以后Counter加一个字段,Memento就要补一个字段。太贫苦了。
- 一种不错的办理办法是:序列化。
- public class Counter {
- private int value;
- public Counter() {
- }
- public void setValue(int value) {
- this.value = value;
- }
- public int getValue() {
- return value;
- }
- public void increment() {
- this.value++;
- }
- public void decrement() {
- this.value--;
- }
- public void restoreMemento(Memento memento) {
- String backup = memento.getBackup();
- Counter tmpCounter = JSON.parseObject(backup, Counter.class);
- this.value = tmpCounter.value;
- }
- public Memento createMemento() {
- String backup = JSON.toJSONString(this);
- return new Memento(backup);
- }
- }
- public class Memento {
- private String backup;
- public Memento(String backup) {
- this.backup = backup;
- }
- public String getBackup() {
- return this.backup;
- }
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |