挺长时间没写博文了,发现如果要写一篇(个人感觉上的)比较完整的博文,还是需要花费挺长的时间的,前阵子忙着一些资料复习,没能动手写笔记心得与实验。虽然写文章挺耗费时间的, 但是所能得到的也很多,在写的过程,会不断推敲内容,考虑如何写得不单自己明白,他人阅读时也能很容易看的明白,并重新整理下记忆内容,极大的加深记忆。所以,还是希望自己能尽可能的整理自己所学吧。谨以此勉励自己。
这篇文章所主要包含行为模式中的2个模式:命令模式&备忘录模式。
-
命令模式是将行为封装成一个命令,然后将命令添加到调用者内,再由调用者发送给真正的处理者。这模式的解释说明对我来说有点绕,不过它的实现原理上很简单,就是
通过调用者调用处理者执行命令
的方式(就这么一句话),在本案例的计算器中,计算器作为调用者,命令是四则运算操作,计算类作为真正处理者,这样就对于计算器与计算类进行了解耦。 -
备忘录模式这是比较简单,就是在不破坏封装的情况下,记录下一个对象的某个状态,以便进行恢复操作。这个实现起来就更为简单了,用一个状态类来记录对象的状态属性,在备忘录类中添加状态类对象(也可以是对象列表,取决于需求),在需要记录操作处调用备忘录捕获,在恢复处调用备忘录还原。在该计算器案例中,备忘录类作为计算类私有内部类存在,即除了该计算类对象,谁也无法操作它。
整个案例关系图如下:
调用者类
package calc;
import impl.AbstractCommand;
public class Calculator {
private AbstractCommand command;
public Calculator(){
}
public void setCommand(AbstractCommand command){
this.command = command;
}
public int compute(int value){
int res = command.execute(value);
System.out.println(res);
return res;
}
public int undo(){
int res = command.undo();
System.out.println("撤销操作,当前结果为" + res);
return res;
}
public int redo(){
int res = command.redo();
System.out.println("取消撤销操作,当前结果为" + res);
return res;
}
public int display(){
int res = command.display();
System.out.println("计算结果为:" + res);
return res;
}
}
处理者类:
package calc;
import java.util.ArrayList;
import java.util.List;
public class Calcute {
private int sum;
private Memento mto;
public Calcute(){
sum = 0;
mto = new Memento();
}
public Calcute(int n){
sum = n;
mto = new Memento(n);
}
public int add(int value){
sum += value;
mto.todo(sum);
return sum;
}
public int substract(int value){
sum -= value;
mto.todo(sum);
return sum;
}
public int multiply(int value){
sum *= value;
mto.todo(sum);
return sum;
}
public int divide(int value){
sum /= value;
mto.todo(sum);
return sum;
}
public int undo(){
this.sum = mto.undo();
return sum;
}
public int redo(){
this.sum = mto.redo();
return sum;
}
public int getSum(){
return sum;
}
private class Memento{
private List<State> history;
private State pre;
private Memento(){
history = new ArrayList<State>();
history.add(new State(0));
}
private Memento(int n){
history = new ArrayList<State>();
history.add(new State(n));
}
private void todo(int value){
history.add(new State(value));
}
private int undo(){
if(history.size() > 1){
pre = history.remove(history.size() -1);
}
return history.get(history.size() -1).getValue();
}
private int redo(){
if(pre != null){
history.add(pre);
pre = null;
}
return history.get(history.size() - 1).getValue();
}
}
}
命令接口:
package impl;
import calc.Calcute;
public abstract class AbstractCommand {
protected Calcute calc;
public AbstractCommand(Calcute calc){
this.calc = calc;
}
public abstract int execute(int value);
public int undo() {
return calc.undo();
}
public int redo() {
return calc.redo();
}
public int display(){
return calc.getSum();
}
}
加法命令:
package command;
import calc.Calcute;
import impl.AbstractCommand;
public class AddCommand extends AbstractCommand{
public AddCommand(Calcute calc){
super(calc);
}
@Override
public int execute(int value) {
return calc.add(value);
}
}
-
整个案例以命令模式+备忘录模式的方式实现,计算操作都是以整数的结果来传递,这点在计算除法会出现问题,而且,对于除法操作上,需要更为详细的处理而不是简单的’’/"来进行!
-
最终我们会发现,案例的耦合点由计算器类与计算类转移到命令与计算类上,可以通过接口的方式,这可以通过优化的方式来优化。
案例github地址,如果有什么错误,欢迎指点~
参考资料:
理解设计模式之----命令模式
菜鸟教程的备忘录模式
如果想系统学习各种编程模式,菜鸟教程上的教程挺详细的~