回到过去的备忘录模式(Nemento Pattern)_PHP_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > PHP > 回到过去的备忘录模式(Nemento Pattern)

回到过去的备忘录模式(Nemento Pattern)

 2014/4/25 17:18:32  home198979  程序员俱乐部  我要评论(0)
  • 摘要:今天学习一个比较少用的备份模式-----备忘录模式。通过名字应该都可以知道其作用了,就是对象或对象属性作备份,方便随便取回。拿打怪来说,开始我有100血,打着打着,剩20了,我想重玩,重新回到100血的状态。用备忘录实现此情形的类图如下:没错,一个简单的功能备忘录标准要用三个类实现。可能你会说为什么要个备忘录管理类,没必要啊,没有管理类功能照样可以实现,但是这样客户端需要关心备忘录,这对迪米特法则是一种亵渎。对高层模块来说,它最希望要做的就是创建一个备份点
  • 标签:模式

今天学习一个比较少用的备份模式-----备忘录模式。通过名字应该都可以知道其作用了,就是对象或对象属性作备份,方便随便取回。拿打怪来说,开始我有100血,打着打着,剩20了,我想重玩,重新回到100血的状态。用备忘录实现此情形的类图如下:



没错,一个简单的功能备忘录标准要用三个类实现。可能你会说为什么要个备忘录管理类,没必要啊,没有管理类功能照样可以实现,但是这样客户端需要关心备忘录,这对迪米特法则是一种亵渎。对高层模块来说,它最希望要做的就是创建一个备份点,然后在需要的时候再恢复到这个备份点就成了,它不用关心到底有没有备忘录这个类。因此才有了备忘录管理类的存在。下面看实现代码:

class="php"><?php
class Gamer {
	private $blood = 0;
	public function getBlood() {
		return $this->blood;
	}
	public function setBlood( $blood ) {
		$this->blood = $blood;
	}
	public function createMemento() {
		return new Memento( $this->blood );
	}
	public function restoreMemento( Memento $memento ) {
		$this->setBlood( $memento->getBlood() );
	}
}


class Memento {
	private $blood = 0;
	public function __construct( $blood ) {
		$this->blood = $blood;
	}
	public function getBlood() {
		return $this->blood;
	}
	public function setBlood( $blood ) {
		$this->blood = $blood;
	}
}

class Caretasker {
	private $memento;
	public function getMemento() {
		return $this->memento;
	}
	public function setMemento( Memento $memento ) {
		$this->memento = $memento;
	}
}

$caretasker = new Caretasker();
$gamer = new Gamer();
$gamer->setBlood(100);
echo "初始血量:100\n";
$caretasker->setMemento($gamer->createMemento());
$gamer->setBlood(20);
echo "打怪后血量:20\n";
$gamer->restoreMemento($caretasker->getMemento());
echo "重玩恢复血量:".$gamer->getBlood();
?>
运行结果:
初始血量:100
打怪后血量:20
重玩恢复血量:100[Finished in 0.3s]

?

?

备忘录模式的定义

备忘录模式提供了一种弥补真实世界缺陷的方法,让“后悔药”在程序的世界中真实可行。其定义为:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之个保存这个状态。这样以后就可将对象恢复到原先保存的状态。其主要由三个角色构成:

1、Originator发起人角色

记录当前时刻的内部状态,负责定义哪些属于备份范围的状态,负责创建和恢复备忘录数据。

2、Memento备忘录角色

负责存储Originator发起人对象的内部状态,在需要的时候提供发起人需要的内部状态。

3、Caretaker备忘录管理员角色

对备忘录进行管理、保存和提供备忘录

?

?

?

备忘录模式的应用

由于备忘录模式有太多的变形和处理方式,每种方式都有它自己的优点和缺点,标准和备忘模式很难在项目中遇到,基本上都有一些变换处理方式。因此,在使用备忘录模式时主要了解如何应用以需要注意哪些事项就成了

?

?

?

备忘录模式的使用场景

1、需要保存和恢复数据的相关状态场景

2、提供一个可回滚操作

3、需要监控的一个副本场景中。例如要监控一个对象的属性,但是监控又不应该作为系统的主业务来调用,它只是边缘应用,即使出现监控不准,错误报警也影响不大,因此一般的做法是备份一个主线程的对象,然后由分析程序来分析。

4、数据库连接的事务管理就是用的备忘录模式。

?

?

备忘录模式的注意事项

1、备忘录的生命期

备忘录创建出来就要在“最近”的代码中使用,要主动管理它的生命周期,建立就要使用,不使用就要立刻删除其引用,等待垃圾回收器对它的回收处理

2、备忘录的性能

不要在频繁建立备份的场景中使用备忘录模式(比如一个for循环中),原因有二:一是控制不了备忘录建立的对象数量,二是大对象的建立是要消耗资源的,系统的性能需要考虑。

?

?

?

备忘录模式的扩展

1、clone方式的备忘录

为保存一个状态写三个类太烦?还记得以前学过的原型模式吗?现在使用原型模式来实现:

<?php
class Gamer {
	private $blood = 0;
	private $backup;
	public function getBlood() {
		return $this->blood;
	}
	public function setBlood( $blood ) {
		$this->blood = $blood;
	}
	public function createMemento() {
		$this->backup = clone $this;
	}
	public function restoreMemento() {
		$this->setBlood( $this->backup->getBlood() );
	}
}


$gamer = new Gamer();
$gamer->setBlood(100);
echo "初始血量:100\n";
$gamer->createMemento();
$gamer->setBlood(20);
echo "打怪后血量:20\n";
$gamer->restoreMemento();
echo "重玩恢复血量:".$gamer->getBlood();
?>
运行结果:
初始血量:100
打怪后血量:20
重玩恢复血量:100[Finished in 0.3s]

?天啊,太简单了是不。但这还是备忘录模式吗?它定义是“在该对象之外保存这个状态”,而现在却把这个状态保存在发起人内部。是的,设计模式定义的诞生过早,它没有想到之后的程序是这么有活力,有远见,而且在面对对象的设计中,即使把一个类封装在另一个类中也是可以做到的,何况一个小小的对象复制,这是它的设计模式完全没有预见到的。注意的是,使用clone方式的备忘录模式,可以使用在比较简单的场景或者比较单一场景中,尽量不要与其他的对象产生严重的耦合关系。

?

2、多状态的备忘录模式

这个就是备份多个属性,在之前的例子除了保存“血量”外,比如再保存个“气量”。

3、多备份的备忘录

4、封装得更好一点

系统管理中,一个备份的数据是完全、绝对不能修改的,它保证数据的洁净,避免数据污染而使备份失去意义

?

?

备忘录模式是设计上的“月光宝盒”,可以让我们回到需要的年代,是程序数据的“后悔药”,吃了它就可以返回上一个状态,是设计人员的定义丸,确保即使在最坏的情况下也能获取最近的对象状态。因此,在设计的时候就不要使用数据库的临时表作为缓存备份数据了,虽然是一个简单的方法,但是它加大了数据库操作的频繁度,把压力下放到数据库了,最好的解决方法就是使用备忘录模式

  • 大小: 7.7 KB
  • 查看图片附件
发表评论
用户名: 匿名