package com.cheng.zenofdesignpatterns.patterns.memento;
import android.view.View;
import com.cheng.zenofdesignpatterns.ZoDPChapterBaseActivity;
import com.cheng.zenofdesignpatterns.patterns.memento.clone.CloneOriginator;
import com.cheng.zenofdesignpatterns.patterns.memento.common.Caretaker;
import com.cheng.zenofdesignpatterns.patterns.memento.common.Originator;
import com.cheng.zenofdesignpatterns.patterns.memento.multistate.MSCaretaker;
import com.cheng.zenofdesignpatterns.patterns.memento.multistate.MSOriginator;
import com.cheng.zenofdesignpatterns.patterns.memento.pursue.Boy;
import com.cheng.zenofdesignpatterns.patterns.memento.pursue.BoyCaretaker;
public class ZoDPMementoActivity extends ZoDPChapterBaseActivity {
@Override
protected void initData() {
mTitleTV.setText("备忘录模式");
String content = "定义:\n" +
"Without violating encapsulation, capture and externalize an object's internal " +
"state so that the object can be restored to this state later.\n" +
"在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后" +
"就可将该对象恢复到原先保存的状态。\n\n" +
"使用场景\n" +
"- 需要保存和恢复数据的相关状态场景\n" +
"- 提供一个可回滚(rollback)的操作\n" +
"- 需要监控的副本场景中\n" +
"- 数据库连接的事物管理就是用的备忘录模式\n\n" +
"注意事项\n" +
"- 备忘录的生命周期\n" +
"备忘录创建出来就要在‘最近’的代码中使用,要主动管理它的生命周期,建立就要使用,不使用" +
"就要立刻删除其引用,等待垃圾回收器对它的回收处理。\n" +
"- 备忘录的性能\n" +
"不要在频繁建立备份的场景中使用备忘录模式(比如一个for循环中),原因有二:一是控制不了" +
"备忘录建立的对象数量;二是大对象的建立是要消耗资源的,系统的性能需要考虑。\n\n" +
"备忘录模式的扩展\n" +
"1. clone方式的备忘录\n" +
"注意 使用clone方式的备忘录模式,可以使用在比较简单的场景或者比较单一的场景中,尽量不" +
"要与其他的对象产生严重的耦合关系。\n" +
"2. 多状态的备忘录模式\n" +
"Spring、Apache工具集commons等都提供了把Bean的所有属性及数值放入到HashMap和把HashMap" +
"的值返回到Bean中的工具类,可用来操作多属性的Bean。\n" +
"注意 如果要设计一个在运行期决定备份状态的框架,则建议采用AOP框架来实现,避免采用动态代" +
"理无谓地增加程序逻辑复杂性。\n" +
"3. 多备份的备忘录\n" +
"检查点(CheckPoint),也就是在备份的时候做的戳记,系统级的备份一般是时间戳,那程序的检" +
"查点该怎样设计呢?一般是一个有意义的字符串。\n" +
"注意 使用Map保存多备份要小心内存溢出问题,该备份一旦生产就装入内存,没有任何销毁的意向," +
"这是非常危险的。因此,在系统设计时,要严格限定备忘录的创建,建议增加Map的上限,否则系统" +
"很容易产生内存溢出情况。\n" +
"4. 封装得更好一点\n" +
"在系统管理上,一个备份的数据是完全、绝对不能修改的,它保证数据的洁净,避免数据污染而使备" +
"份失去意义。在设计领域中,也存在着同样的问题,备份是不能被篡改的,也就是说需要缩小备份出" +
"的备忘录的阅读权限,保证只能是发起人可读就成了,那怎么才能做到这一点呢?使用内置类。\n" +
"双接口设计:在系统设计时,如果考虑对象的安全问题,可以提供两个接口,一个是业务的正常接口," +
"实现必要的业务逻辑,叫做宽接口;另外一个接口是空接口,什么方法都没有,其目的是提供给子系" +
"统外的模块访问,比如容器对象,这个叫窄接口,由于窄接口中没有提供任何操作数据的方法,因此" +
"相对来说比较安全。\n\n" +
"最佳实践\n" +
"在设计的时候不要使用数据库的临时表作为缓存备份数据了,虽然是一个简单的办法,但是它加大了" +
"数据库操作的频繁度,把压力放到数据库了,最好的解决办法就是使用备忘录模式。";
mContentTV.setText(content);
}
@Override
public void onClick(View v) {
// 1. 模拟电影《Next》男主角追求女主角过程
// 声明出男主角
Boy boy = new Boy();
// 声明出备忘录的管理者
BoyCaretaker caretaker = new BoyCaretaker();
// 初始化当前状态
boy.setState("心情很棒!");
System.out.println("=====男孩现在的状态======");
System.out.println(boy.getState());
// 需要记录下当前状态呀
caretaker.setMemento(boy.createMemento());
// 男孩去追女孩,改变状态
boy.changeState();
System.out.println("\n=====男孩追女孩子后的状态======");
System.out.println(boy.getState());
// 追女孩失败,恢复原状
boy.restoreMemento(caretaker.getMemento());
System.out.println("\n=====男孩恢复后的状态======");
System.out.println(boy.getState());
// 2. 通用备忘录模式演示
// 定义出发起人
Originator originator = new Originator();
// 定义出备忘录管理员
Caretaker caretaker1 = new Caretaker();
// 创建一个备忘录
caretaker1.setMemento(originator.createMemento());
// 恢复一个备忘录
originator.restoreMemento(caretaker1.getMemento());
// 3. clone方式的备忘录
// 定义发起人
CloneOriginator originatorClone = new CloneOriginator();
// 建立初始状态
originatorClone.setState("初始状态...");
System.out.println("初始状态是:" + originatorClone.getState());
// 建立备份
originatorClone.createMemento();
// 修改状态
originatorClone.setState("修改后的状态");
System.out.println("修改后的状态是:" + originatorClone.getState());
// 恢复原有状态
originatorClone.restoreMemento();
System.out.println("恢复后的状态是:" + originatorClone.getState());
// 4. 多状态备忘录
// 定义出发起人
MSOriginator msOriginator = new MSOriginator();
// 定义出备忘录管理员
MSCaretaker msCaretaker = new MSCaretaker();
// 初始化
msOriginator.setState1("中国");
msOriginator.setState1("强盛");
msOriginator.setState1("繁荣");
System.out.println("===初始化状态===\n" + msOriginator);
// 创建一个备忘录
msCaretaker.setMemento(msOriginator.createMemento());
// 修改状态值
msOriginator.setState1("软件");
msOriginator.setState1("架构");
msOriginator.setState1("优秀");
System.out.println("===修改后状态===\n" + msOriginator);
// 恢复一个备忘录
msOriginator.restoreMemento(msCaretaker.getMemento());
System.out.println("===恢复后状态===\n" + msOriginator);
// 5. 多备份使用内置类封装得更好一点
}
}