定义:
备忘录模式又叫做快照模式或Token模式,在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
UML类图:
角色: ? ? ? ?
? ? ? ? 1.发起人(GameRole):负责创建一个备忘录,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。发起人可以根据需要决定备忘录存储自己的哪些内部状态。
? ? ? ? 2.备忘录(RoleStateSaveBox):负责存储发起人对象的内部状态,并可以防止发起人以外的其他对象访问备忘录。备忘录有两个接口:管理者只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。发起人却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。
? ? ? ? 3.管理者(GameRoleStateManager):负责存取备忘录,不能对的内容进行访问或者操作。
适用性:
? ? ?? 必须保存一个对象在某一个时刻的(部分)状态, 这样以后需要时它才能恢复到先前的状态。 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
?
思考:
1. 备忘录和发起人的关系和特征是什么?
答:备忘录必须包含发起人的所有属性,类似镜像;
2. 如果发起人含有非常多的属性,远超3个,如30个,备忘录的构造函数,难道要有30个参数吗?
????有待进一步思考实践
3. 管理者的角色思考?
答:负责存取?发起人可以直接存,直接取,管理者存在的唯一理由是需要这个“中介”,从这个中介里getState
4.?可以防止发起人以外的其他对象访问备忘录,怎样防止呢?
5. 现实中应用:
? ? ? ? 游戏存档;
优缺点:
优点:
? ? ? ? 1、有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这时,使用备忘录模式可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以恰当地保持封装的边界。?
? ? ? ? 2、本模式简化了发起人类。发起人不再需要管理和保存其内部状态的一个个版本,客户端可以自行管理他们所需要的这些状态的版本。
缺点:
? ? ? 1、如果发起人角色的状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象会很昂贵。
? ? ? 2、当负责人角色将一个备忘录存储起来的时候,负责人可能并不知道这个状态会占用多大的存储空间,从而无法提醒用户一个操作是否很昂贵。
PHP例程:
<?php
//例程1
/**
* 发起人类
*/
class Sponsor{
public $time = 36000;
public $title = "奋斗者";
public $money = 0;
public function subTime(){
$this->time --;
}
public function addMoney(){
$this->money += 1000;
}
public function changeTitle($title){
$this->title = $title;
}
/**
* 备份当前的基础数据属性
*/
public function backup(){
return new Backup($this->time,$this->money,$this->title);
}
/**
* 数据还原
*
*/
public function reback(Backup $backup){
$this->time = $backup->time;
$this->title = $backup->title;
$this->money = $backup->money;
}
}
/**
* 存储类
*/
class Backup{
public $time;
public $title;
public $money;
public function __construct($time,$money,$title){
$this->time = $time;
$this->title = $title;
$this->money = $money;
}
}
/**
* 管理者类
*/
class Manager{
public $data;
}
//客户端应用
$Sponsor = new Sponsor();
//备份初始状态
$Manager = new Manager();
$Manager->data = $Sponsor -> backup();
while($Sponsor->time > 0){
$Sponsor -> addMoney();
$Sponsor -> subTime();
if($Sponsor->money >= 1000000)
$Sponsor -> changeTitle("骄傲者");
if($Sponsor->money >= 10000000)
$Sponsor -> changeTitle("能力者");
if($Sponsor->money >= 100000000)
$Sponsor -> changeTitle("成功者");
}
var_dump($Sponsor);
//还原初始状态
$Sponsor->reback($Manager->data);
var_dump($Sponsor);
?例程2
<?php
//备忘录
class Memento{
public $id;
public $name;
public $liveLevel;
function __construct($id,$name,$liveLevel){
$this->id = $id;
$this->name = $name;
$this->liveLevel = $liveLevel;
}
}
//备忘录管理器
class Originator{
public static $mementos = array();
private static $instance = null;
//单例模式确保只有一个管理器
private function __construct(){
}
//返回单例对象
static function getInstance(){
if(!(self::$instance instanceOf slef)){
self::$instance = new self();
}
return self::$instance;
}
//存备忘录
function setMemento($id,Memento $memento){
self::$mementos[$id] = $memento;
}
//取备忘录
function getMemento($id){
return self::$mementos[$id];
}
}
//创建者,玩家,可存取自身状态
class Player{
private static $i = 0; //静态变量累加用于给$id赋值
public $id; //每个对象独一无二,用于保存状态备忘录到管理器
private $name; //姓名
private $liveLevel; //生命值
function __construct($name){
$this->name = $name;
$this->id = self::$i;
self::$i++;
}
//初始化
function init(){
$this->liveLevel = 100;
}
//生命值减少10
function damage(){
$this->liveLevel -=10;
}
//显示现有状态
function displayState(){
echo "姓 名:".$this->name."<br/>";
echo "生命值:".$this->liveLevel."<br/>";
}
//保存状态到一个备忘录中,该备忘录将被放置到管理器中
function saveState(){
$originator = Originator::getInstance();
$originator->setMemento($this->id,new Memento($this->id,$this->name,$this->liveLevel));
}
//恢复备忘录
function getState(){
$originator = Originator::getInstance();
$memento = $originator->getMemento($this->id);
$this->id = $memento->id;
$this->name = $memento->name;
$this->liveLevel = $memento->liveLevel;
}
}
//测试
//创建、初始化角色并显示状态
$player = new Player("张三");
$player->init();
$player->displayState(); //生命值100
//开始游戏前存档
$player->saveState();
//开始游戏,收到伤害生命值减少,显示状态
$player->damage();
$player->damage();
$player->displayState(); //生命值80
//回档恢复原来状态,显示状态
$player->getState();
$player->displayState(); //生命值100
?>
|