2019-11-02 22:11:39 +08:00
|
|
|
|
## 备忘录(Memento)
|
|
|
|
|
|
|
|
|
|
### Intent
|
|
|
|
|
|
|
|
|
|
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
|
|
|
|
|
|
|
|
|
|
### Class Diagram
|
|
|
|
|
|
|
|
|
|
- Originator:原始对象
|
|
|
|
|
- Caretaker:负责保存好备忘录
|
2019-11-30 14:55:15 +08:00
|
|
|
|
- Memento:备忘录,存储原始对象的的状态。备忘录实际上有两个接口,一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。
|
2019-11-02 22:11:39 +08:00
|
|
|
|
|
2019-12-06 10:11:23 +08:00
|
|
|
|
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/50678f34-694f-45a4-91c6-34d985c83fee.png"/> </div><br>
|
2019-11-02 22:11:39 +08:00
|
|
|
|
|
|
|
|
|
### Implementation
|
|
|
|
|
|
|
|
|
|
以下实现了一个简单计算器程序,可以输入两个值,然后计算这两个值的和。备忘录模式允许将这两个值存储起来,然后在某个时刻用存储的状态进行恢复。
|
|
|
|
|
|
|
|
|
|
实现参考:[Memento Pattern - Calculator Example - Java Sourcecode](https://www.oodesign.com/memento-pattern-calculator-example-java-sourcecode.html)
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
/**
|
|
|
|
|
* Originator Interface
|
|
|
|
|
*/
|
|
|
|
|
public interface Calculator {
|
|
|
|
|
|
|
|
|
|
// Create Memento
|
|
|
|
|
PreviousCalculationToCareTaker backupLastCalculation();
|
|
|
|
|
|
|
|
|
|
// setMemento
|
|
|
|
|
void restorePreviousCalculation(PreviousCalculationToCareTaker memento);
|
|
|
|
|
|
|
|
|
|
int getCalculationResult();
|
|
|
|
|
|
|
|
|
|
void setFirstNumber(int firstNumber);
|
|
|
|
|
|
|
|
|
|
void setSecondNumber(int secondNumber);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
/**
|
|
|
|
|
* Originator Implementation
|
|
|
|
|
*/
|
|
|
|
|
public class CalculatorImp implements Calculator {
|
|
|
|
|
|
|
|
|
|
private int firstNumber;
|
|
|
|
|
private int secondNumber;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public PreviousCalculationToCareTaker backupLastCalculation() {
|
|
|
|
|
// create a memento object used for restoring two numbers
|
|
|
|
|
return new PreviousCalculationImp(firstNumber, secondNumber);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void restorePreviousCalculation(PreviousCalculationToCareTaker memento) {
|
|
|
|
|
this.firstNumber = ((PreviousCalculationToOriginator) memento).getFirstNumber();
|
|
|
|
|
this.secondNumber = ((PreviousCalculationToOriginator) memento).getSecondNumber();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int getCalculationResult() {
|
|
|
|
|
// result is adding two numbers
|
|
|
|
|
return firstNumber + secondNumber;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setFirstNumber(int firstNumber) {
|
|
|
|
|
this.firstNumber = firstNumber;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setSecondNumber(int secondNumber) {
|
|
|
|
|
this.secondNumber = secondNumber;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
/**
|
|
|
|
|
* Memento Interface to Originator
|
|
|
|
|
*
|
|
|
|
|
* This interface allows the originator to restore its state
|
|
|
|
|
*/
|
|
|
|
|
public interface PreviousCalculationToOriginator {
|
|
|
|
|
int getFirstNumber();
|
|
|
|
|
int getSecondNumber();
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
/**
|
|
|
|
|
* Memento interface to CalculatorOperator (Caretaker)
|
|
|
|
|
*/
|
|
|
|
|
public interface PreviousCalculationToCareTaker {
|
|
|
|
|
// no operations permitted for the caretaker
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
/**
|
|
|
|
|
* Memento Object Implementation
|
|
|
|
|
* <p>
|
|
|
|
|
* Note that this object implements both interfaces to Originator and CareTaker
|
|
|
|
|
*/
|
|
|
|
|
public class PreviousCalculationImp implements PreviousCalculationToCareTaker,
|
|
|
|
|
PreviousCalculationToOriginator {
|
|
|
|
|
|
|
|
|
|
private int firstNumber;
|
|
|
|
|
private int secondNumber;
|
|
|
|
|
|
|
|
|
|
public PreviousCalculationImp(int firstNumber, int secondNumber) {
|
|
|
|
|
this.firstNumber = firstNumber;
|
|
|
|
|
this.secondNumber = secondNumber;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int getFirstNumber() {
|
|
|
|
|
return firstNumber;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int getSecondNumber() {
|
|
|
|
|
return secondNumber;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
/**
|
|
|
|
|
* CareTaker object
|
|
|
|
|
*/
|
|
|
|
|
public class Client {
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
// program starts
|
|
|
|
|
Calculator calculator = new CalculatorImp();
|
|
|
|
|
|
|
|
|
|
// assume user enters two numbers
|
|
|
|
|
calculator.setFirstNumber(10);
|
|
|
|
|
calculator.setSecondNumber(100);
|
|
|
|
|
|
|
|
|
|
// find result
|
|
|
|
|
System.out.println(calculator.getCalculationResult());
|
|
|
|
|
|
|
|
|
|
// Store result of this calculation in case of error
|
|
|
|
|
PreviousCalculationToCareTaker memento = calculator.backupLastCalculation();
|
|
|
|
|
|
|
|
|
|
// user enters a number
|
|
|
|
|
calculator.setFirstNumber(17);
|
|
|
|
|
|
|
|
|
|
// user enters a wrong second number and calculates result
|
|
|
|
|
calculator.setSecondNumber(-290);
|
|
|
|
|
|
|
|
|
|
// calculate result
|
|
|
|
|
System.out.println(calculator.getCalculationResult());
|
|
|
|
|
|
|
|
|
|
// user hits CTRL + Z to undo last operation and see last result
|
|
|
|
|
calculator.restorePreviousCalculation(memento);
|
|
|
|
|
|
|
|
|
|
// result restored
|
|
|
|
|
System.out.println(calculator.getCalculationResult());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```html
|
|
|
|
|
110
|
|
|
|
|
-273
|
|
|
|
|
110
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### JDK
|
|
|
|
|
|
|
|
|
|
- java.io.Serializable
|