备忘录模式
在对一个对象进行操作时,希望这个操作时可回退的。那么就要保存每一步操作时前一步对象的状态。
这个时候可以用备忘录模式。
组成部分
- 需要记录状态的类
- 保存对象当前状态和历史状态的类--备忘录类
- 管理备忘录类的类----提供对备忘录中的对象进行增删改查的方法
1.需要记录状态的类
1 @Data 2 public class BasePo { 3 private String id; 4 } 5 6 @Data 7 @EqualsAndHashCode(callSuper=false) 8 public class Student extends BasePo{ 9 private String name; 10 private int age; 11 private String grade; 12 }
2.备忘录类--(保存历史状态时为了减少存储所需空间将对象序列化成了json)
1 public class Memento<T extends BasePo> { 2 private T currentState; 3 4 private LinkedList<String> stateJson; 5 6 public T getCurrentState() { 7 return currentState; 8 } 9 10 @SuppressWarnings("unchecked") 11 public void setCurrentState(Object currentState) { 12 this.currentState = (T) currentState; 13 } 14 15 public LinkedList<String> getStateJson() { 16 return stateJson; 17 } 18 19 public void setStateJson(LinkedList<String> stateJson) { 20 this.stateJson = stateJson; 21 } 22 23 @Override 24 public String toString(){ 25 Field[] fields = currentState.getClass().getDeclaredFields(); 26 StringBuilder builder = new StringBuilder(); 27 for (Field field : fields) { 28 field.setAccessible(true); 29 String firstLetter = field.getName().substring(0,1).toUpperCase(); 30 String getMethodName = "get"+firstLetter+field.getName().substring(1); 31 try { 32 Method getMethod = currentState.getClass().getMethod(getMethodName, new Class[] {}); 33 builder.append(" 字段["); 34 builder.append(field.getName()); 35 builder.append("] has value "); 36 builder.append(getMethod.invoke(currentState, new Object[] {})); 37 } catch (Exception e) { 38 39 } 40 41 } 42 return builder.toString(); 43 } 44 }
备忘录类的管理类
public class MementoManage<T extends BasePo> { private HashMap<String, Memento<T>> map = new HashMap<String, Memento<T>>(); public Class<?> getTClass(T t) { return t.getClass(); } public void add(T entity) throws IllegalAccessException, InvocationTargetException, InstantiationException{ if (map.containsKey(entity.getId())) { update(entity); }else { Memento<T> memento = new Memento<T>(); Object t = this.getTClass(entity).newInstance(); BeanUtils.copyProperties(t, entity); memento.setCurrentState(t); memento.setStateJson(new LinkedList<String>()); map.put(entity.getId(), memento); System.out.println(memento.toString()); } } public void update(T entity) throws IllegalAccessException, InvocationTargetException, InstantiationException{ Memento<T> memento = map.get(entity.getId()); String json = new Gson().toJson(memento.getCurrentState()); memento.getStateJson().addLast(json); Object t = this.getTClass(entity).newInstance(); BeanUtils.copyProperties(t, entity); memento.setCurrentState(t); System.out.println(memento.toString()); } public void cancel(T entity){ Memento<T> memento = map.get(entity.getId()); if (memento.getStateJson().size()==0) { System.out.println("沒有可回退的操作"); System.out.println(memento.toString()); }else { String json = memento.getStateJson().getLast().toString(); memento.setCurrentState(new Gson().fromJson(json, Student.class)); memento.getStateJson().removeLast(); System.out.println(memento.toString()); } } public void delete(T entity){ if (map.containsKey(entity.getId())) { map.remove(entity.getId()); } } }
测试类
1 public static void main(String[] args) throws IllegalAccessException, 2 InvocationTargetException, InstantiationException { 3 Student student = new Student(); 4 student.setId(UUID.randomUUID().toString()); 5 student.setAge(19); 6 student.setName("小红"); 7 student.setGrade("大一"); 8 MementoManage<Student> manage = new MementoManage<Student>(); 9 10 manage.add(student); 11 12 student.setAge(22); 13 manage.update(student); 14 15 manage.cancel(student); 16 17 student.setGrade("初三"); 18 manage.update(student); 19 20 manage.cancel(student); 21 manage.delete(student); 22 23 }
测试结果
字段[name] has value 小红 字段[age] has value 19 字段[grade] has value 大一 字段[name] has value 小红 字段[age] has value 22 字段[grade] has value 大一 字段[name] has value 小红 字段[age] has value 19 字段[grade] has value 大一 字段[name] has value 小红 字段[age] has value 22 字段[grade] has value 初三 字段[name] has value 小红 字段[age] has value 19 字段[grade] has value 大一