★☆☆☆☆
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
结构图
角色
- 备忘录(Memento)角色:备忘录角色存储“备忘发起角色”的内部状态。“备忘发起角色”根据需要决定备忘录角色存储“备忘发起角色”的哪些内部状态。为了防止“备忘发起角色”以外的其他对象访问备忘录。备忘录实际上有两个接口,“备忘录管理者角色”只能看到备忘录提供的窄接口——对于备忘录角色中存放的属性是不可见的。“备忘发起角色”则能够看到一个宽接口——能够得到自己放入备忘录角色中的状态(属性)。
- 原发器(Originator)角色:“备忘发起者角色”创建一个备忘录,用以记录当前时刻它的内部状态。在需要时使用备忘录恢复内部状态。
- 备忘录管理者(Caretaker)角色:负责保存好备忘录。不能对备忘录的内容进行操作或检查。
动机
在软件构建过程中集合,某些对象的状态在转换过程中,可能由于某种需要,要求程序能够回溯到对象之前处于某个点时的状态。如果使用一些公有接口来让其他对象得到对象的状态,便会暴露对象的细节实现。
如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的封装性。
意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。
示意性代码
示意性代码
Module MainApp
Public Sub Main()
Dim o As Originator = New Originator
o.State = "On"
'Store internal state
Dim c As New Caretaker
c.Memento = o.CreateMemento()
'Continue changing originator
o.State = "Off"
'Restore saved state
o.SetMemento(c.Memento)
'Wait for user
Console.ReadLine()
End Sub
End Module
Public Class Originator
Private _state As String
Public Property State() As String
Get
Return _state
End Get
Set(ByVal value As String)
_state = value
Console.WriteLine("State = " & _state)
End Set
End Property
Public Sub SetMemento(ByVal memento As Memento)
Console.WriteLine("Restoring state:")
State = memento.State
End Sub
Public Function CreateMemento() As Memento
Return New Memento(State)
End Function
End Class
Public Class Memento
Public Sub New(ByVal state As String)
Me._state = state
End Sub
Private _state As String
Public Property State() As String
Get
Return _state
End Get
Set(ByVal value As String)
_state = value
End Set
End Property
End Class
Public Class Caretaker
Private _memento As Memento
Public Property Memento() As Memento
Get
Return _memento
End Get
Set(ByVal value As Memento)
_memento = value
End Set
End Property
End Class
一个实例
下面的备忘录代码演示了暂时保存销售场景对象(Salesprospect)的内部状态,然后恢复销售场景对象(Salesprospect)的内部状态。
实例代码
Module MainApp
Public Sub Main()
Dim o As Originator = New Originator
o.State = "On"
'Store internal state
Dim c As New Caretaker
c.Memento = o.CreateMemento()
'Continue changing originator
o.State = "Off"
'Restore saved state
o.SetMemento(c.Memento)
'Wait for user
Console.ReadLine()
End Sub
End Module
Public Class Originator
Private _state As String
Public Property State() As String
Get
Return _state
End Get
Set(ByVal value As String)
_state = value
Console.WriteLine("State = " & _state)
End Set
End Property
Public Sub SetMemento(ByVal memento As Memento)
Console.WriteLine("Restoring state:")
State = memento.State
End Sub
Public Function CreateMemento() As Memento
Return New Memento(State)
End Function
End Class
Public Class Memento
Public Sub New(ByVal state As String)
Me._state = state
End Sub
Private _state As String
Public Property State() As String
Get
Return _state
End Get
Set(ByVal value As String)
_state = value
End Set
End Property
End Class
Public Class Caretaker
Private _memento As Memento
Public Property Memento() As Memento
Get
Return _memento
End Get
Set(ByVal value As Memento)
_memento = value
End Set
End Property
End Class
Memento Pattern模式的几个要点:
1、备忘录(Memento)存储原发器(Originator)对象的内部状态,在需要时回复原发器状态。Memento模式适用于“由原发器管理,却又必须存储在原发器之外的信息”
2、在实现Memento模式中,要防止原发器以外的对象访问备忘录对象。备忘录对象有两个接口,一个为原发器使用的宽接口;一个为其他对象使用的窄接口。
3、在实现Memento模式时,要考虑拷贝对象状态的效率问题,如果对象开销比较大,可以采用某种增量式改变来改进Memento模式。
我的理解
封装对象状态变化,支持状态保存/恢复。
参考资料
《C#面向对象设计模式纵横谈系列课程(21)》 李建中老师