Memento_备忘录模式_PHP语言描述

Memento_备忘录模式定义:

在不破坏封装性的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。

一个备忘录是一个对象,它储存一个对象在某个瞬间的内部状态,后者被称为备忘录的原发器。

从定义看,备忘录模式最重要的功能就是记录某个对象某个瞬间的状态,作为备忘之用。而我们获取了这个备份数据有什么用呐,其实就是为了恢复到那个瞬间的状态,虽然不是一定会恢复,但是目的就是为了恢复。这也是很多人理解备忘录模式的时候,忽略掉的地方,他们太关注备忘,而忽略了恢复,这样是不全面的理解。

应用Memento_备忘录模式解决问题的思路:

在写命令模式的时候,写了一个简单的计算器的实例。现在我们要回想一下,当时也完成了撤销及恢复命令的功能。但那时候的实现是基于对应的命令操作来实现的,即加法的对应是减法,减法对应的就是加法,互操作即可完成功能。现在用备忘录模式来解决这个问题试试,因为备忘录模式最大的用处就是获取某个点的状态,并回复。下面是一个命令模式和备忘录模式混合使用的实例,用命令模式来实现具体各种算法的操作,使用备忘录模式来完成撤销及恢复的功能。


<?php
/**
 * Memento_备忘录模式_PHP语言描述
 */

interface Memento{
	
}

/**
 * 定义一个命令的接口
 */
interface Command{
	
	/**
	 * 执行命令
	 */
	public function execute();
	
	/**
	 * 撤销命令,恢复到备忘录对象记录的状态
	 * @param memento 备忘录对象
	 */
	public function undo($memento);
	
	/**
	 * 重做命令,恢复到备忘录对象记录的状态
	 * @param memento 备忘录对象
	 */
	public function redo($memento);
	
	/**
	 * 创建保存原发器对象状态的备忘录独享
	 * @return  创建好的备忘录对象
	 */
	public function createMemento();
 }
 
 /**
  * 操作运算的接口
  */
 interface OperationApi{
 	
 	/**
 	 * 获取计算完成后的结果
 	 * @return  计算完成后的结果
 	 */
 	public function getResult();
 	
 	/**
 	 * 执行加法
 	 * @param num 需要加的数
 	 */
 	public function add($num);
 	
 	/**
 	 * 执行减法
 	 * @param num 需要减的数
 	 */
 	public function substract($num);
 	
 	/**
 	 * 创建保存原发器对象状态的备忘录对象
 	 * @return  创建好的备忘录对象
 	 */
 	public function createMemento();
 	
 	/**
 	 * 重新设置原发器对象状态,让其会到备忘录对象记录的状态
 	 * @param memento 记录有原发器状态的备忘录对象
 	 */
 	public function setMemento($memento);
 }
 
 /**
  * 命令对象的公共对象,实现各个命令对象的公共方法
  */
 class AbstractCommand implements Command{
 	/**
 	 * 具体的功能实现,这里不需要实现
 	 */
	public function execute(){
		
	}
 	
 	/**
 	 * 持有真正的命令实现者对象
 	 */
 	protected  $operation = null;
 	
 	public function setOperation($operation){
 		$this->operation = $operation;
 	}
 	
 	public function createMemento(){
 		return $this->operation->createMemento();
 	}
 	
 	public function redo($memento){
 		$this->operation->setMemento($memento);
 	}
 	
 	public function undo($memento){
 		$this->operation->setMemento($memento);
 	}
 }
 

/**
 * 具体的加法命令类实现,由于继承于公共的命令类,只要实现与自己相关的部分即可
 */
class AddCommand extends AbstractCommand{
	private $opeNum;
	
	public function __construct($opeNum){
		$this->opeNum = $opeNum;
	}
	
	public function execute(){
		$this->operation->add($this->opeNum);
	}
}

/**
 * 具体的减法命令类实现,由于继承于公共的命令类,只要实现与自己相关的部分即可
 */
class SubstractCommand extends AbstractCommand{
	private $opeNum;
	
	public function __construct($opeNum){
		$this->opeNum = $opeNum;
	}
	
	public function execute(){
		$this->operation->substract($this->opeNum);
	}
}

/**
 * 运算类,真正实现加减法运算
 */
class Operation implements OperationApi{
	/**
	 * 记录运算的结果
	 */
	private $result;
	
	public function getResult(){
		return $this->result;
	}
	
	public function add($num){
		$this->result += $num;
	}
	
	public function substract($num){
		$this->result -= $num;
	}
	
	public function createMemento(){
		return $m = new MementoImpl($this->result);
	}
	
	public function setMemento($memento){
		$this->result = $memento->getResult();
	}
}

class MementoImpl implements Memento{
	private $result = 0;
	
	public function __construct($result){
		$this->result = $result;
	}
	
	public function getResult(){
		return $this->result;
	}
}

/**
 * 计算器类,计算器上有加法按钮,减法按钮,还有撤销和恢复的按钮
 */

class Calculator{
	/**
	 * 命令的操作历史记录,在撤销时用
	 */
	private $undoCmds = array();
	
	/**
	 * 命令被撤销的历史记录,在恢复时用
	 */
	private $redoCmds = array();
	
	/**
	 * 命令操作对应的备忘录对象的历史记录,在撤销时用
	 * 数组有两个元素,第一个是命令执行前的状态,第二个是命令执行后的状态
	 */
	private $undoMementos = array();
	
	/**
	 * 被撤销命令操作对应的备忘录对象的历史记录,在撤销时用
	 * 数组有两个元素,第一个是命令执行前的状态,第二个是命令执行后的状态
	 */
	private $redoMementos = array();
	
	private $addCmd = null;
	private $substractCmd = null;
	
	public function setAddCmd($addCmd){
		$this->addCmd = $addCmd;
	}
	
	public function setSubstractCmd($substractCmd){
		$this->substractCmd = $substractCmd;
	}
	
	public function addPressed(){
		//获取对应的备忘录对象,并保存在相应的历史记录中
		$m1 = $this->addCmd->createMemento();
		
		//执行命令
		$this->addCmd->execute();
		//把操作记录到历史记录中
		array_push($this->undoCmds, $this->addCmd);
		
		//获取执行命令后的备忘录对象
		$m2 = $this->addCmd->createMemento();
		//设置到撤销的历史记录中
		array_push($this->undoMementos,array($m1,$m2));
	}
	
	public function substractPressed(){
		//获取对应的备忘录对象,并保存在相应的历史记录中
		$m1 = $this->substractCmd->createMemento();
		
		//执行命令
		$this->substractCmd->execute();
		//把操作记录到历史记录中
		array_push($this->undoCmds,$this->substractCmd);
		
		//获取执行命令后的备忘录对象
		$m2 = $this->substractCmd->createMemento();
		//设置到撤销的历史记录中
		array_push($this->undoMementos,array($m1,$m2));		
	}
	
	public function undoPressed(){
		if(count($this->undoCmds) > 0){
			//取出最后一个命令来撤销
			$cmd = $this->undoCmds[count($this->undoCmds) - 1];
			//获取对应的备忘录对象
			$ms = $this->undoMementos[count($this->undoCmds) - 1];
			//撤销
			$cmd->undo($ms[0]);
			
			//如果还有恢复的功能,那就把这个命令记录到恢复的历史记录中
			array_push($this->redoCmds,$cmd);
			//把相应的备忘录对象也添加过去
			array_push($this->redoMementos,$ms);
			
			//然后把最后一个命令删除
			array_pop($this->undoCmds);
			//把相应的备忘录对象也删除
			array_pop($this->undoMementos);
		}
		else {
			echo "已经没有可撤销的命令了";
		}
	}
	
	public function redoPressed(){
		if(count($this->redoCmds) > 0){
			//取出最后一个命令来重做
			$cmd = $this->redoCmds[count($this->redoCmds) - 1];
			//取出相应的备忘录对象
			$ms = $this->redoMementos[count($this->redoCmds) - 1];
			
			//重做
			$cmd->redo($ms[1]);
			
			//把这个命令记录到可撤销的历史记录中
			array_push($this->undoCmds,$cmd);
			//把相应的备忘录对象也添加过去
			array_push($this->undoMementos,$ms);
			
			//然后把最后一个命令删除
			array_pop($this->redoCmds);
			array_pop($this->redoMementos);
		}
		else{
			echo "已经没有可恢复的命令了";
		}
	}
}

//1.组装命令和接收者
//创建接收者
$operation = new Operation();

//创建命令
$addCmd = new AddCommand(5);
$substractCmd = new SubstractCommand(3);

//组装命令和接收者
$addCmd->setOperation($operation);
$substractCmd->setOperation($operation);

//2.把命令设置到持有者,就是计算器中
$calculator = new Calculator();
$calculator->setAddCmd($addCmd);
$calculator->setSubstractCmd($substractCmd);

//3.模拟按下按钮,测试一下
$calculator->addPressed();
echo "<br>一次加法运算后的结果为:".$operation->getResult();
$calculator->addPressed();
echo "<br>一次加法运算后的结果为:".$operation->getResult();
$calculator->addPressed();
echo "<br>一次加法运算后的结果为:".$operation->getResult();
$calculator->substractPressed();
echo "<br>一次减法运算后的结果为:".$operation->getResult();
$calculator->substractPressed();
echo "<br>一次减法运算后的结果为:".$operation->getResult();

//测试撤销
$calculator->undoPressed();
echo "<br>一次撤销运算后的结果为:".$operation->getResult();
$calculator->undoPressed();
echo "<br>一次撤销运算后的结果为:".$operation->getResult();

//测试恢复
$calculator->redoPressed();
echo "<br>一次恢复运算后的结果为:".$operation->getResult();
$calculator->redoPressed();
echo "<br>一次恢复运算后的结果为:".$operation->getResult();
 ?>


转载于:https://my.oschina.net/cniiliuqi/blog/64988

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值