“状态变化” 模式
- 在组件构建过程中,某些对象的状态经常面临变化,如何对这些变化进行有效的管理,同时又维持高层模块的稳定?”状态变化“模式为这一问题提供了一种解决方法。
- 典型模式
- State
- Memento
一、场景分析
有时有必要记录一个对象的内部状态。为了允许用户取消不确定的操作或从错误中恢复过来,需要实现检查点和取消机制,而要实现这些机制,你必须事先将状态信息保存在某处,这样才能将对象恢复到它们先前的状态。但是对象通常封装了其部分或所有的状态信息,使得其状态不能被其他对象访问,也就不可能在该对象之外保存其状态。而暴露其内部状态又将违反封装的原则,可能有损应用的可靠性和可扩展性。
例如,考虑一个图形编辑器,它支持图形对象间的连线。用户可用一条直线连接两个矩形,而当用户移动任意一个矩形时,这两个矩形仍能保持连接。在移动过程中,编辑器自动伸展这条直线以保持该连接。

一个保持对象间连接关系的方法是使用一个约束解释系统。我们可将这一功能封装在一个ConstraintSolver对象中。ConstraintSolver在时,记录这些连接并产生描述它们的数学方程。当用户生成一个连接或修改图形时,ConstraintSolver就求解这些方程。并根据它的计算结果重新调整图形,使各个对象保持正确的连接。
支持取消操作的一个显而易见的方法是,在每次移动时保存移动的距离,而在取消这次移动时该对象移回相等的距离。然而,这不能保证所有的对象都会出现在它们原先出现的地方。加入在移动过程中导致某连接中有一些问题,在这种情况下,简单地将矩形移回到它原来的位置并不一定能得到预想的效果。

一般来说,ConstraintSolver的公共接口可能不足以精确地逆转它对其他对象的作用。为重建先前的状态,取消操作机制必须与ConstraintSolver更紧密的结合,但我们同时也应避免将ConstraintSolver的内部暴露给取消机制。
我们可用备忘录模式解决这一问题。一个备忘录(memento)是一个对象,它存储另一个对象在某个瞬间的内部状态,而后者称为备忘录的原发器(originator)。当需要设置原发器的检查点时,取消操作机制会向原发器请求一个备忘录。原发器用描述当前状态的信息初始化该备忘录。只有原发器可以向备忘录中存取信息,备忘录对其他的对象“不可见”。
在刚才讨论的图形编辑器的例子中,ConstraintSolver可作为一个原发器。下面的事件序列描述了取消操作的过程:
- 作为移动操作的一个附加操作,编辑器向ConstraintSolver请求一个备忘录。
- ConstraintSolver创建并返回一个备忘录,在这个例子中该备忘录是SolverState类的一个实例。SolverState备忘录包含一些描述ConstraintSolver的内部等式和变量当前状态的数据结构。
- 此后当用户取消移动操作时,编辑器将SolverState备忘录送回给ConstraintSolver。
- 根据SolverState备忘录中的信息,ConstraintSolver改变它的内部结构以精确地将它的等式和变量返回到它们各自先前的状态。
二、动机
在软件构件过程中,某些对象的状态在转换过层中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象获得对象的状态,会暴露对象的细节实现。
如何实现对象状态的良好保存与恢复,但同时又不会因此而破环对象本身的封装性,是需要解决的问题。
三、模式定义
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
四、结构

参与者:
- Memento(备忘录,如SolverState)
- 备忘录存储原发器对象的内部状态。原发器根据需要局定备忘录存储原发器的哪些内部状态。
- 防止原发器以外的其他对象访问备忘录。备忘录实际上有两个接口,管理者(caretaker)只能看到备忘录的窄接口——它只能将备忘录传递给其他对象。相反,原发器能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。理想的情是只允许生成备忘录的那个原发器访问本备忘录的内部状态。
- Originator(原发器,如ConstraintSolver)
- 原发器创建一个备忘录,用以记录当前时刻它的内部状态。
- 使用备忘录恢复内部状态。
- Caretaker(负责人,如undo mechanism)
- 负责保存好备忘录
- 不能对备忘录的内容进行操作或检查
186

被折叠的 条评论
为什么被折叠?



