我的 WinClock 项目系列之四 (Memento 模式的应用)
动机 (Motivation)
在软件的构建过程中,某些对象的状态在转换过程中,可能由于某种需要,
要求程序能够回溯到对象之前某个点时的状态,如果使用一些公有接口来让
其他对象得到对象的状态,便会暴露对象的细节实现。
如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的
封装性。
意图 (Intent)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在这个对象之外保存
这个状态。这样就可以将对象恢复到原先保存的状态。
《设计模式》———— GOF
从类图可以看出, ClockOption, MainForm, RemindData, RemindOparate 都实现了
一个 IMementoCapable 接口,这个接口定义如下:
很简单,只是能够把一个对象的状态保存为一个Properties对象,或者利用一个Properties
对象把这个对象的状态恢复到之前的状态。
这样做是很有必要的,比如对于 OptionForm,是需要可以预览的,这样用户在更改了一个
设置后马上就可以看到效果。比如拖动 Size 滑块,马上可以看到变大或者变小的效果。这样
的功能用到的还不少,使用 Memento 在窗体加载前先保存好原有的状态,在取消后就可以很
方便到恢复到之前的状态。下面是 Option 菜单执行的操作:
分钟检测一次是否有提醒任务。
属性的。主要是通过Get<T>,Set<T>两个泛型方法:
李建忠 C#面向对象设计模式纵横谈(21):(行为型模式) Memento 备忘录模式
SharpDevelop 3.0 源代码
在软件的构建过程中,某些对象的状态在转换过程中,可能由于某种需要,
要求程序能够回溯到对象之前某个点时的状态,如果使用一些公有接口来让
其他对象得到对象的状态,便会暴露对象的细节实现。
如何实现对象状态的良好保存与恢复?但同时又不会因此而破坏对象本身的
封装性。
意图 (Intent)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在这个对象之外保存
这个状态。这样就可以将对象恢复到原先保存的状态。
《设计模式》———— GOF
从类图可以看出, ClockOption, MainForm, RemindData, RemindOparate 都实现了
一个 IMementoCapable 接口,这个接口定义如下:
1
// IMementoCapable.cs
2
public interface IMementoCapable {
3
Properties CreateMemento();
4
void SetMemento(Properties properties);
5
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
很简单,只是能够把一个对象的状态保存为一个Properties对象,或者利用一个Properties
对象把这个对象的状态恢复到之前的状态。
这样做是很有必要的,比如对于 OptionForm,是需要可以预览的,这样用户在更改了一个
设置后马上就可以看到效果。比如拖动 Size 滑块,马上可以看到变大或者变小的效果。这样
的功能用到的还不少,使用 Memento 在窗体加载前先保存好原有的状态,在取消后就可以很
方便到恢复到之前的状态。下面是 Option 菜单执行的操作:
1
// OptionElement.cs
2
internal class OptionElement : Element {
3
public OptionElement(Mediator mediator, ToolStripMenuItem source)
4
: base(mediator) {
5
base.command = new MenuItemCommand(source);
6
}
7![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
protected override void OnExecute() {
9
using (OptionForm optionForm = new OptionForm(base.mainForm)) {
10
Core.Properties memento = mainForm.CreateMemento();
11
byte previewOpacity = clockOpt.PreviewOpacity;
12
if (optionForm.ShowDialog() == DialogResult.Cancel) {
13
mainForm.SetMemento(memento);
14
base.clockOpt.PreviewOpacity = previewOpacity;
15
mainForm.RefreshSkin();
16
} else { // OK clicked
17
clockOpt.PreviewOpacity = clockOpt.Opacity;
18
Point location = mainForm.Location;
19
mainForm.CheckBounds(ref location);
20
mainForm.Location = location;
21
mainForm.RefreshWindow();
22
}
23
}
24
}
25
}
下面是 Remind 菜单要执行的操作:![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
1
// RemindElement.cs
2
internal class RemindElement : Element {
3
private Timer timerRemind;
4![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
public RemindElement(Mediator mediator, ToolStripMenuItem source)
6
: base(mediator) {
7
base.command = new MenuItemCommand(source);
8
timerRemind = new Timer();
9
this.timerRemind.Interval = 60000;
10
this.timerRemind.Tick += TimerRemindOnTick;
11
this.timerRemind.Enabled = clockOpt.HaveRemind;
12
}
13![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
protected override void OnExecute() {
15
using (RemindListForm frmRemind = new RemindListForm(remindOperate)) {
16
Core.Properties savedProperties = remindOperate.CreateMemento();
17
if (frmRemind.ShowDialog() == DialogResult.OK) {
18
Core.Properties properties = remindOperate.CreateMemento();
19
PropertyService.Set("WinClock.RemindOperate", properties);
20
clockOpt.HaveRemind = frmRemind.HaveRemind;
21
} else { // User Canceled
22
remindOperate.SetMemento(savedProperties);
23
}
24
}
25
}
26![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
27
protected internal override void OnStatusChanged() {
28
if (clockOpt.HaveRemind) {
29
if (!this.timerRemind.Enabled) {
30
this.timerRemind.Start();
31
}
32
} else {
33
if (!this.timerRemind.Enabled) {
34
this.timerRemind.Stop();
35
}
36
}
37
}
38![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
39
protected override void Dispose(bool disposing) {
40
if (disposing) {
41
try {
42
timerRemind.Tick -= TimerRemindOnTick;
43
timerRemind.Dispose();
44
} finally {
45
timerRemind = null;
46
}
47
}
48![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
49
base.Dispose(disposing);
50
}
51![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
52
private void TimerRemindOnTick(object sender, EventArgs e) {
53
remindOperate.CheckRemindList();
54
}
55
}
RemindOperate 类实现的是对定时提醒任务的检测和保存,它利用一个 Timer, 每隔一![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
28
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
29
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
30
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
31
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
32
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
33
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
34
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
35
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
36
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
37
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
38
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
39
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
40
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
41
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
42
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
43
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
44
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
45
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
46
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
47
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
48
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
49
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
50
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
51
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
52
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
53
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
54
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
55
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
分钟检测一次是否有提醒任务。
1
// RemindOperate.cs
2
[Serializable()]
3
public struct RemindData : IMementoCapable {
4
public string remindTitle;
5
public string remindMode;
6
public string remindTime;
7
public string remindText;
8
public string programPath;
9
public string musicPath;
10
public bool showMessage;
11
public bool executeprogram;
12
public bool playSound;
13
public bool closeComputer;
14![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
IMementoCapable Members
47
}
48![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
49
[Serializable()]
50
public class RemindOperate : IMementoCapable, ILacalizable {
51
private List<RemindData> remindDataList;
52
public static readonly string YearMonthDayTimeFmt = "yyyy-MM-dd HH:mm";
53
public static readonly string YearMonthDayFmt = "yyyy-MM-dd";
54
public static readonly string MonthDayFmt = "MM-dd";
55
public static readonly string DayFmt = "dd";
56
public static readonly string TimeFmt = "HH:mm";
57![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
58
public static readonly Dictionary<DayOfWeek, string> Days;
59
static RemindOperate() {
60
Days = new Dictionary<DayOfWeek, string>();
61
Initialize();
62
}
63![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
64
public RemindOperate() {
65
remindDataList = new List<RemindData>();
66
ResourceService.LocalizeList.Add(this);
67
}
68![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
69
public List<RemindData> RemindDataList {
70
get {
71
return this.remindDataList;
72
}
73
}
74![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
75
public void CheckRemindList() {
76
string currentTime = DateTime.Now.ToString(YearMonthDayTimeFmt);
77
currentTime += " " + Days[DateTime.Now.DayOfWeek];
78
for (int index = 0; index < remindDataList.Count; ++index) {
79
RemindData rmdData = remindDataList[index];
80
string remindTime = rmdData.remindTime;
81![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
82
if (currentTime.IndexOf(remindTime) != -1) {
83
ShowRemindInfo(index);
84
}
85
}
86
}
87![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
88
public void ShowRemindInfo(int index) {
89
RemindData rmdData = remindDataList[index];
90
if (rmdData.closeComputer) {
91
MessageService.ShowShutdownMessage();
92
} else {
93
if (rmdData.playSound) {
94
SoundPlayer soundPlayer = new SoundPlayer(rmdData.musicPath);
95
soundPlayer.Play();
96
}
97![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
98
if (rmdData.showMessage) {
99
MessageService.ShowRemindMessage(rmdData);
100
}
101![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
102
if (rmdData.executeprogram) {
103
Process proc = new Process();
104
proc.StartInfo.FileName = rmdData.programPath;
105
proc.StartInfo.Arguments = string.Empty;
106
proc.Start();
107
}
108
}
109
}
110![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
111
private static void Initialize() {
112
Days.Clear();
113
Days.Add(DayOfWeek.Sunday, ResourceService.GetString("CSharpCode.Core.RemindOperate.Sunday"));
114
Days.Add(DayOfWeek.Monday, ResourceService.GetString("CSharpCode.Core.RemindOperate.Monday"));
115
Days.Add(DayOfWeek.Tuesday, ResourceService.GetString("CSharpCode.Core.RemindOperate.Tuesday"));
116
Days.Add(DayOfWeek.Wednesday, ResourceService.GetString("CSharpCode.Core.RemindOperate.Wednesday"));
117
Days.Add(DayOfWeek.Thursday, ResourceService.GetString("CSharpCode.Core.RemindOperate.Thursday"));
118
Days.Add(DayOfWeek.Friday, ResourceService.GetString("CSharpCode.Core.RemindOperate.Friday"));
119
Days.Add(DayOfWeek.Saturday, ResourceService.GetString("CSharpCode.Core.RemindOperate.Saturday"));
120
}
121![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
122
IMementoCapable Members
148![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
149
ILacalizable Members
156
}
在这个软件中,Properties类是Memento的关键,同时也是以后要讲的持久化存储的关键。这里只要看他是如何设置和取得一个![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
47
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
48
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
49
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
50
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
51
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
52
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
53
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
54
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
55
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
56
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
57
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
58
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
59
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
60
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
61
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
62
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
63
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
64
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
65
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
66
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
67
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
68
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
69
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
70
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
71
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
72
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
73
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
74
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
75
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
76
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
77
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
78
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
79
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
80
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
81
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
82
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
83
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
84
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
85
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
86
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
87
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
88
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
89
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
90
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
91
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
92
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
93
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
94
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
95
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
96
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
97
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
98
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
99
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
100
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
101
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
102
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
103
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
104
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
105
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
106
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
107
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
108
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
109
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
110
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
111
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
112
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
113
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
114
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
115
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
116
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
117
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
118
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
119
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
120
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
121
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
122
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
148
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
149
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
156
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
属性的。主要是通过Get<T>,Set<T>两个泛型方法:
1
// Part of Properties.cs
2
public class Properties {
3
Dictionary<string, object> properties = new Dictionary<string, object>();
4
protected EventHandlerList Events = new EventHandlerList();
5
private static readonly object EventPropertiesChanged = new object();
6![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
public string this[string property] {
8
get {
9
return Convert.ToString(Get(property));
10
}
11
set {
12
Set(property, value);
13
}
14
}
15![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
16
public event EventHandler<PropertyChangedEventArgs> PropertyChanged {
17
add {
18
this.Events.AddHandler(EventPropertiesChanged, value);
19
}
20
remove {
21
this.Events.RemoveHandler(EventPropertiesChanged, value);
22
}
23
}
24![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
25
public string[] Elements {
26
get {
27
lock (properties) {
28
List<string> ret = new List<string>();
29
foreach (KeyValuePair<string, object> property in properties) {
30
ret.Add(property.Key);
31
}
32
return ret.ToArray();
33
}
34
}
35
}
36![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
37
public object Get(string property) {
38
lock (properties) {
39
object val;
40
properties.TryGetValue(property, out val);
41
return val;
42
}
43
}
44![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
45
public void Set<T>(string property, T value) {
46
T oldValue = default(T);
47
lock (properties) {
48
if (!properties.ContainsKey(property)) {
49
properties.Add(property, value);
50
} else {
51
oldValue = Get<T>(property, value);
52
properties[property] = value;
53
}
54
}
55
OnPropertyChanged(new PropertyChangedEventArgs(this, property, oldValue, value));
56
}
57![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
58
public bool Contains(string property) {
59
lock (properties) {
60
return properties.ContainsKey(property);
61
}
62
}
63![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
64
public int Count {
65
get {
66
lock (properties) {
67
return properties.Count;
68
}
69
}
70
}
71![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
72
public bool Remove(string property) {
73
lock (properties) {
74
return properties.Remove(property);
75
}
76
}
77![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
78
public override string ToString() {
79
lock (properties) {
80
StringBuilder sb = new StringBuilder();
81
sb.Append("[Properties:{");
82
foreach (KeyValuePair<string, object> entry in properties) {
83
sb.Append(entry.Key);
84
sb.Append("=");
85
sb.Append(entry.Value);
86
sb.Append(",");
87
}
88
sb.Append("}]");
89
return sb.ToString();
90
}
91
}
92![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
93
public T Get<T>(string property, T defaultValue) {
94
lock (properties) {
95
object o;
96
if (!properties.TryGetValue(property, out o)) {
97
properties.Add(property, defaultValue);
98
return defaultValue;
99
}
100![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
101
if (o is string && typeof(T) != typeof(string)) {
102
TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
103
try {
104
o = c.ConvertFromInvariantString(o.ToString());
105
} catch (Exception ex) {
106
MessageBox.Show("Error loading property '" + property + "': " + ex.Message);
107
o = defaultValue;
108
}
109
properties[property] = o; // store for future look up
110
} else if (o is ArrayList && typeof(T).IsArray) {
111
ArrayList list = (ArrayList)o;
112
Type elementType = typeof(T).GetElementType();
113
Array arr = System.Array.CreateInstance(elementType, list.Count);
114
TypeConverter c = TypeDescriptor.GetConverter(elementType);
115
try {
116
for (int i = 0; i < arr.Length; ++i) {
117
if (list[i] != null) {
118
arr.SetValue(c.ConvertFromInvariantString(list[i].ToString()), i);
119
}
120
}
121
o = arr;
122
} catch (Exception ex) {
123
MessageBox.Show("Error loading property '" + property + "': " + ex.Message);
124
o = defaultValue;
125
}
126
properties[property] = o; // store for future look up
127
} else if (!(o is string) && typeof(T) == typeof(string)) {
128
TypeConverter c = TypeDescriptor.GetConverter(typeof(T));
129
if (c.CanConvertTo(typeof(string))) {
130
o = c.ConvertToInvariantString(o);
131
} else {
132
o = o.ToString();
133
}
134
}
135
try {
136
return (T)o;
137
} catch (NullReferenceException) {
138
// can happen when configuration is invalid -> o is null and a value type is expected
139
return defaultValue;
140
}
141
}
142
}
143![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
144
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) {
145
EventHandler<PropertyChangedEventArgs> handler = this.Events[EventPropertiesChanged] as EventHandler<PropertyChangedEventArgs>;
146
if (handler != null) {
147
handler(this, e);
148
}
149
}
150
151
// Other methods
152
}
参考资料:![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
28
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
29
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
30
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
31
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
32
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
33
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
34
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
35
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
36
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
37
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
38
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
39
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
40
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
41
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
42
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
43
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
44
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
45
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
46
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
47
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
48
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
49
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
50
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
51
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
52
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
53
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
54
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
55
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
56
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
57
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
58
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
59
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
60
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
61
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
62
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
63
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
64
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
65
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
66
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
67
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
68
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
69
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
70
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
71
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
72
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
73
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
74
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
75
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
76
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
77
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
78
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
79
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
80
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
81
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
82
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
83
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
84
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
85
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
86
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
87
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
88
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
89
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
90
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
91
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
92
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
93
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
94
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
95
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
96
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
97
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
98
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
99
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
100
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
101
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
102
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
103
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
104
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
105
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
106
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
107
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
108
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
109
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
110
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
111
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
112
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
113
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
114
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
115
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
116
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
117
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
118
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
119
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
120
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
121
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
122
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
123
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
124
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
125
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
126
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
127
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
128
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
129
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
130
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
131
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
132
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
133
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
134
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
135
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
136
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
137
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
138
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
139
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
140
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
141
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
142
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
143
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
144
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
145
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
146
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
147
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
148
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
149
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
150
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
151
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
152
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
李建忠 C#面向对象设计模式纵横谈(21):(行为型模式) Memento 备忘录模式
SharpDevelop 3.0 源代码
这是微软技术的一贯特点,使用简单。但是如果要深入的话,还是要投入不少精力的