`
亚当爱上java
  • 浏览: 696792 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Android设计模式系列(5)--SDK源码之备忘录模式

 
阅读更多

定义(源于GoF《设计模式》):在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

 

涉及角色

 

1.Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。

 

2.Memento(备忘录):负责存储Originator对象的内部状态,并可以防止Originator以外 的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘 录的宽接口,允许它访问返回到先前状态所需要的所有数据。

 

3.Caretaker(管理者):负责保存好备忘录Memento,不能对Memento的内容进行访问或者操作。

备忘录模式,在工作代码中,要么不用,要么经常用到。
以保存游戏进度为例,在游戏角色大战Boss前将该角色的状态存储,与Boss作战后角色的各项能力会下降,如果没有通关,则可利用备忘录进行恢复到战前状态。

 

游戏角色类

package com.zyh.designpattern.memento;

public class PlayRole {
	private int vitality;
	private int aggressivity;
	private int defencivity;

	public PlayRole(int vitality, int aggressivity, int defencivity) {
		super();
		this.vitality = vitality;
		this.aggressivity = aggressivity;
		this.defencivity = defencivity;
	}

	public PlayRole() {
	}

	public int getVitality() {
		return vitality;
	}

	public void setVitality(int vitality) {
		this.vitality = vitality;
	}

	public int getAggressivity() {
		return aggressivity;
	}

	public void setAggressivity(int aggressivity) {
		this.aggressivity = aggressivity;
	}

	public int getDefencivity() {
		return defencivity;
	}

	public void setDefencivity(int defencivity) {
		this.defencivity = defencivity;
	}

	public RoleMemento createMemento() {
		RoleMemento memento = new RoleMemento();
		memento.setAggressivity(aggressivity);
		memento.setDefencivity(defencivity);
		memento.setVitality(vitality);
		return memento;
	}

	public void setMemento(RoleMemento memento) {
		this.aggressivity = memento.getAggressivity();
		this.defencivity = memento.getDefencivity();
		this.vitality = memento.getVitality();
	}

	public void showState() {
		System.out.println("攻击力:" + this.aggressivity + "|防御力:"
				+ this.defencivity + "|生命力:" + this.vitality);
	}
}
 

 

 

备忘录类:

package com.zyh.designpattern.memento;

public class RoleMemento {
	private int vitality;
	private int aggressivity;
	private int defencivity;

	public int getVitality() {
		return vitality;
	}

	public void setVitality(int vitality) {
		this.vitality = vitality;
	}

	public int getAggressivity() {
		return aggressivity;
	}

	public void setAggressivity(int aggressivity) {
		this.aggressivity = aggressivity;
	}

	public int getDefencivity() {
		return defencivity;
	}

	public void setDefencivity(int defencivity) {
		this.defencivity = defencivity;
	}
}
 

 

 

管理者类

package com.zyh.designpattern.memento;

public class Caretaker {
	RoleMemento memento;

	public RoleMemento getMemento() {
		return memento;
	}

	public void setMemento(RoleMemento memento) {
		this.memento = memento;
	}
}
 

 

 

客户端:

package com.zyh.designpattern.memento;

public class Client {
	public static void main(String[] args) {
		// 测试程序
		// 新建角色
		PlayRole role = new PlayRole(100, 100, 100);
		// 新建管理者
		Caretaker taker = new Caretaker();
		// 角色初始状态
		System.out.println("游戏刚开始,角色各属性:");
		role.showState();
		// 利用备忘录模式保存当前状态
		System.out.println("\n【保存游戏状态!】\n");
		taker.setMemento(role.createMemento());
		role.setAggressivity(20);
		role.setDefencivity(30);
		role.setVitality(0);
		// 大战过后,角色能力值下降
		System.out.println("与Boss对战后,角色各项能力已大大下降:");
		role.showState();
		// 恢复保存的角色状态
		role.setMemento(taker.getMemento());
		System.out.println("\n【恢复保存的角色状态!】");
		System.out.println("\n恢复后角色的当前状态:");
		role.showState();
	}
}
 

 
本文今天就Canvas的一个save(),restore()操作分析一下,但是有一点,看完本文,如果不懂备忘录模式的,应该还是不懂,但是canvas是android的一场大戏,说一说它的特色,对深入学习android绝对有帮助。
学习备忘录模式,通过保存状态,恢复状态的内部实现,对了解一些莫名其妙的看上去无用其实很重要的操作有拨开云雾见青天的作用。

 

1.意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到先前保存的状态。
热门词汇:标记 状态 备忘录 原发器

2.结构和代码

组 织者,把原发器的状态State(全部或者部分状态,一般是变量的值),通过CreateMemento()方法保存起来,继续运行后,等待合适的时机, 在通过SetMemento()方法可以再次恢复到之前的状态。在这个过程中,我们并没有对这些状态做任何的访问和设置,实际上这些状态都是私有的,对外 是禁止访问的,我们只是通过Memento对象的两个最简单的方法就达到了这个效果。Memento经常写成Originator的内部类。
在Android中,Canvas有两个方法 save()和restore()方法再做图形变换的时候使用的非常多,因为涉及到跨语言的问题,我不好就认定这个用的是备忘录模式,但是它的这种思想绝对是备忘录的思想。


我们来读一读它源代码的注释吧,首先看save()保存状态:

public class Canvas {
    /**
     * Saves the current matrix and clip onto a private stack. Subsequent
     * calls to translate,scale,rotate,skew,concat or clip Rect,clipPath
     * will all operate as usual, but when the balancing call to restore()
     * is made, those calls will be forgotten, and the settings that existed
     * before the save() will be reinstated.
     */
    /**
     *保存当前的矩阵和剪裁到一个私有的堆栈,其实矩阵和剪裁就是当前Canvas的状态State
     */
    public native int save();
}
 

  再看恢复状态restore():

public class Canvas {
    /**
     * This call balances a previous call to save(), and is used to remove all
     * modifications to the matrix/clip state since the last save call. It is
     * an error to call restore() more times than save() was called.
     */
    /**
     * 移除自上次保存操作后所做的修改,恢复到之前的状态,因为是堆栈实现,所以pull操作不能不等于push操作,save()和restore()应该成对使用,否则恢复的状态就很有可能是错误的
     */
    public native void restore();
}
 

  从上面的两个方法中,它们实现了自我状态的恢复,实际上我们只是执行了两个没有接触任何内部信息的方法,实际上这两个方法就是在操作我们看不到的这些内部状态信息。

3.效果
(1).保持封装边界,把很复杂的原发器的内部信息对外部其他对象隐藏起来。
(2).简化的原发器,把状态操作无形中转化到客户手里,简化了原发器的某些实现。
(3).也要注意注意备忘录的管理代价。

 

备忘录模式的优点和缺点
一、备忘录模式的优点

 

1、有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这时,

 

使用备忘录模式可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以恰当地保持封装的边界。

 

2、本模式简化了发起人类。发起人不再需要管理和保存其内部状态的一个个版本,客户端可以自行管理他们所需

 

要的这些状态的版本。

 

3、当发起人角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。

 

二、备忘录模式的缺点:

 

1、如果发起人角色的状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象会很昂贵。

 

2、当负责人角色将一个备忘录 存储起来的时候,负责人可能并不知道这个状态会占用多大的存储空间,从而无法提醒用户一个操作是否很昂贵。

 

3、当发起人角色的状态改变的时候,有可能这个协议无效。如果状态改变的成功率不高的话,不如采取“假如”协议模式。    
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics