Memento 提供了保存对象状态的能力,似乎没有什么好说的。
C#code
1// Memento
2
3// Intent: "Without violating encapsulation, capture and externalize an
4// object's internal state so that an object can be restored to this
5// state later."
6
7// For further information, read "Design Patterns", p283, Gamma et al.,
8// Addison-Wesley, ISBN:0-201-63361-2
9
10/**//* Notes:
11 * We often have client code that wishes to record the current state of an
12 * object, without being interested in the actual data values (this is
13 * needed for undo and checkpointing). To support this behavior, we can have
14 * the object record its internal data in a helper class called a memento, and
15 * the client code can treat this as an opaque store of the object's state.
16 * At some later point, the client can pass the memento back into the object,
17 * to restore it to the previous state.
18 */
19
20namespace Memento_DesignPattern
21{
22 using System;
23
24 class Originator
25 {
26 private double manufacturer=0;
27 private double distributor = 0;
28 private double retailer = 0;
29
30 public void MakeSale(double purchasePrice)
31 {
32 // We assume sales are divided equally amount the three
33 manufacturer += purchasePrice * .40;
34 distributor += purchasePrice *.3;
35 retailer += purchasePrice *.3;
36 // Note: to avoid rounding errors for real money handling
37 // apps, we should be using decimal integers
38 // (but hey, this is just a demo!)
39 }
40
41 public Memento CreateMemento()
42 {
43 return (new Memento(manufacturer, distributor, retailer));
44 }
45
46 public void SetMemento(Memento m)
47 {
48 manufacturer = m.A;
49 distributor = m.B;
50 retailer = m.C;
51 }
52 }
53
54 class Memento
55 {
56 private double iA;
57 private double iB;
58 private double iC;
59
60 public Memento(double a, double b, double c)
61 {
62 iA = a;
63 iB = b;
64 iC = c;
65 }
66
67 public double A
68 {
69 get
70 {
71 return iA;
72 }
73 }
74
75 public double B
76 {
77 get
78 {
79 return iB;
80 }
81 }
82
83 public double C
84 {
85 get
86 {
87 return iC;
88 }
89 }
90 }
91
92 class caretaker
93 {
94
95 }
96
97 /**//// <summary>
98 /// Summary description for Client.
99 /// </summary>
100 public class Client
101 {
102 public static int Main(string[] args)
103 {
104 Originator o = new Originator();
105
106 // Assume that during the course of running an application
107 // we we set various data in the originator
108 o.MakeSale(45.0);
109 o.MakeSale(60.0);
110
111 // Now we wish to record the state of the object
112 Memento m = o.CreateMemento();
113
114 // We make further changes to the object
115 o.MakeSale(60.0);
116 o.MakeSale(10.0);
117 o.MakeSale(320.0);
118
119 // Then we decide ot change our minds, and revert to the saved state (and lose the changes since then)
120 o.SetMemento(m);
121
122 return 0;
123 }
124 }
125}
126
127
1// Memento
2
3// Intent: "Without violating encapsulation, capture and externalize an
4// object's internal state so that an object can be restored to this
5// state later."
6
7// For further information, read "Design Patterns", p283, Gamma et al.,
8// Addison-Wesley, ISBN:0-201-63361-2
9
10/**//* Notes:
11 * We often have client code that wishes to record the current state of an
12 * object, without being interested in the actual data values (this is
13 * needed for undo and checkpointing). To support this behavior, we can have
14 * the object record its internal data in a helper class called a memento, and
15 * the client code can treat this as an opaque store of the object's state.
16 * At some later point, the client can pass the memento back into the object,
17 * to restore it to the previous state.
18 */
19
20namespace Memento_DesignPattern
21{
22 using System;
23
24 class Originator
25 {
26 private double manufacturer=0;
27 private double distributor = 0;
28 private double retailer = 0;
29
30 public void MakeSale(double purchasePrice)
31 {
32 // We assume sales are divided equally amount the three
33 manufacturer += purchasePrice * .40;
34 distributor += purchasePrice *.3;
35 retailer += purchasePrice *.3;
36 // Note: to avoid rounding errors for real money handling
37 // apps, we should be using decimal integers
38 // (but hey, this is just a demo!)
39 }
40
41 public Memento CreateMemento()
42 {
43 return (new Memento(manufacturer, distributor, retailer));
44 }
45
46 public void SetMemento(Memento m)
47 {
48 manufacturer = m.A;
49 distributor = m.B;
50 retailer = m.C;
51 }
52 }
53
54 class Memento
55 {
56 private double iA;
57 private double iB;
58 private double iC;
59
60 public Memento(double a, double b, double c)
61 {
62 iA = a;
63 iB = b;
64 iC = c;
65 }
66
67 public double A
68 {
69 get
70 {
71 return iA;
72 }
73 }
74
75 public double B
76 {
77 get
78 {
79 return iB;
80 }
81 }
82
83 public double C
84 {
85 get
86 {
87 return iC;
88 }
89 }
90 }
91
92 class caretaker
93 {
94
95 }
96
97 /**//// <summary>
98 /// Summary description for Client.
99 /// </summary>
100 public class Client
101 {
102 public static int Main(string[] args)
103 {
104 Originator o = new Originator();
105
106 // Assume that during the course of running an application
107 // we we set various data in the originator
108 o.MakeSale(45.0);
109 o.MakeSale(60.0);
110
111 // Now we wish to record the state of the object
112 Memento m = o.CreateMemento();
113
114 // We make further changes to the object
115 o.MakeSale(60.0);
116 o.MakeSale(10.0);
117 o.MakeSale(320.0);
118
119 // Then we decide ot change our minds, and revert to the saved state (and lose the changes since then)
120 o.SetMemento(m);
121
122 return 0;
123 }
124 }
125}
126
127
“保存状态”,似乎有点似曾相识,我们在Singleton曾经序列化保存过其状态并回复。
序列化的话相当于重新构建对象,好处是程序结束后都可以保存状态。显然Memento是相对比较轻量级的解决方案,保存状态类可以使用原型模式的Clone方法。也可以与Command模式共同使用为其提供Undo的状态保存。
二进制序列化例子
static void Main (string[] args)
{
Book book = new Book("Day and Night", 30.0f, "Bruce");
using(FileStream fs = new FileStream(@"C:\book.dat", FileMode.Create))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, book);
}
book = null;
using(FileStream fs = new FileStream(@"C:\book.dat", FileMode.Open))
{
BinaryFormatter formatter = new BinaryFormatter();
book = (Book)formatter.Deserialize(fs);//在这里大家要注意咯,他的返回值是object
}
}
static void Main (string[] args)
{
Book book = new Book("Day and Night", 30.0f, "Bruce");
using(FileStream fs = new FileStream(@"C:\book.dat", FileMode.Create))
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, book);
}
book = null;
using(FileStream fs = new FileStream(@"C:\book.dat", FileMode.Open))
{
BinaryFormatter formatter = new BinaryFormatter();
book = (Book)formatter.Deserialize(fs);//在这里大家要注意咯,他的返回值是object
}
}
XMLSerilizeExample
1. XML serialization serializes only the public fields and property values of an object into an XML stream
2. XML serialization does not include type information
3. XML serialization requires a default constructor to be declared in the class that is to be serialized
4. XML serialization requires all properties that are to be serialized as read write properties. Read only properties are not serialized.
[C#]
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
// This is the class that will be serialized.
public class OrderedItem
{
public string ItemName;
public string Description;
public decimal UnitPrice;
public int Quantity;
public decimal LineTotal;
// A custom method used to calculate price per item.
public void Calculate()
{
LineTotal = UnitPrice * Quantity;
}
}
public class Test{
public static void Main()
{
Test t = new Test();
// Write a purchase order.
t.SerializeObject("simple.xml");
t.DeserializeObject("simple.xml");
}
private void SerializeObject(string filename)
{
Console.WriteLine("Writing With XmlTextWriter");
XmlSerializer serializer =
new XmlSerializer(typeof(OrderedItem));
OrderedItem i = new OrderedItem();
i.ItemName = "Widget";
i.Description = "Regular Widget";
i.Quantity = 10;
i.UnitPrice = (decimal) 2.30;
i.Calculate();
// Create an XmlTextWriter using a FileStream.
Stream fs = new FileStream(filename, FileMode.Create);
XmlWriter writer =
new XmlTextWriter(fs, Encoding.Unicode);
// Serialize using the XmlTextWriter.
serializer.Serialize(writer, i);
writer.Close();
}
private void DeserializeObject(string filename)
{
Console.WriteLine("Reading with XmlReader");
// Create an instance of the XmlSerializer specifying type and namespace.
XmlSerializer serializer = new
XmlSerializer(typeof(OrderedItem));
// A FileStream is needed to read the XML document.
FileStream fs = new FileStream(filename, FileMode.Open);
XmlReader reader = new XmlTextReader(fs);
// Declare an object variable of the type to be deserialized.
OrderedItem i;
// Use the Deserialize method to restore the object's state.
i = (OrderedItem) serializer.Deserialize(reader);
// Write out the properties of the object.
Console.Write(
i.ItemName + "\t" +
i.Description + "\t" +
i.UnitPrice + "\t" +
i.Quantity + "\t" +
i.LineTotal);
}
}
1. XML serialization serializes only the public fields and property values of an object into an XML stream
2. XML serialization does not include type information
3. XML serialization requires a default constructor to be declared in the class that is to be serialized
4. XML serialization requires all properties that are to be serialized as read write properties. Read only properties are not serialized.
[C#]
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
// This is the class that will be serialized.
public class OrderedItem
{
public string ItemName;
public string Description;
public decimal UnitPrice;
public int Quantity;
public decimal LineTotal;
// A custom method used to calculate price per item.
public void Calculate()
{
LineTotal = UnitPrice * Quantity;
}
}
public class Test{
public static void Main()
{
Test t = new Test();
// Write a purchase order.
t.SerializeObject("simple.xml");
t.DeserializeObject("simple.xml");
}
private void SerializeObject(string filename)
{
Console.WriteLine("Writing With XmlTextWriter");
XmlSerializer serializer =
new XmlSerializer(typeof(OrderedItem));
OrderedItem i = new OrderedItem();
i.ItemName = "Widget";
i.Description = "Regular Widget";
i.Quantity = 10;
i.UnitPrice = (decimal) 2.30;
i.Calculate();
// Create an XmlTextWriter using a FileStream.
Stream fs = new FileStream(filename, FileMode.Create);
XmlWriter writer =
new XmlTextWriter(fs, Encoding.Unicode);
// Serialize using the XmlTextWriter.
serializer.Serialize(writer, i);
writer.Close();
}
private void DeserializeObject(string filename)
{
Console.WriteLine("Reading with XmlReader");
// Create an instance of the XmlSerializer specifying type and namespace.
XmlSerializer serializer = new
XmlSerializer(typeof(OrderedItem));
// A FileStream is needed to read the XML document.
FileStream fs = new FileStream(filename, FileMode.Open);
XmlReader reader = new XmlTextReader(fs);
// Declare an object variable of the type to be deserialized.
OrderedItem i;
// Use the Deserialize method to restore the object's state.
i = (OrderedItem) serializer.Deserialize(reader);
// Write out the properties of the object.
Console.Write(
i.ItemName + "\t" +
i.Description + "\t" +
i.UnitPrice + "\t" +
i.Quantity + "\t" +
i.LineTotal);
}
}