Head First Design patterns笔记-Observer Patterns (从TFS的Project alerts功能看观察者模式) . Team foundation server中提供了一个非常适用的功能就是project alerts.在team explorer中打开一个项目,右键菜单中有一个project alerts菜单项,点击会弹出一个对话框,你可以选择自己要接受的project alert的类别(发送project alert的一些规则)和自己的email地址,当当前项目发生的变化或者发生的事件满足上述你订阅的规则时,系统就会给你发送邮件通知你TFS中你所关心的项目发生了怎样的变化。想着跟踪项目中的变化,这应该是最方便的途径了,订阅了以后TFS会自动通知你相关的信息,你在也不会自己逐个文件查看是否发生了改变了。如果不在需要跟踪项目的信息,只要推订project alerts就可以了。
定义:Strategy pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependencies are notified and updated automatically.
背景介绍:Team foundation server中提供了一个非常适用的功能就是project alerts.在team explorer中打开一个项目,右键菜单中有一个project alerts菜单项,点击会弹出一个对话框,你可以选择自己要接受的project alert的类别(发送project alert的一些规则)和自己的email地址,当当前项目发生的变化或者发生的事件满足上述你订阅的规则时,系统就会给你发送邮件通知你TFS中你所关心的项目发生了怎样的变化。想着跟踪项目中的变化,这应该是最方便的途径了,订阅了以后TFS会自动通知你相关的信息,你再也不用自己逐个文件查看是否发生了改变了。如果不再需要跟踪项目信息,只要退订project alerts就可以了。
![](https://www.cnblogs.com/images/cnblogs_com/netboy/ProjectAlert.PNG)
VS自动生成的类图:
![](https://www.cnblogs.com/images/cnblogs_com/netboy/Observer1.PNG)
![](https://www.cnblogs.com/images/cnblogs_com/netboy/Observer2.PNG)
实例代码:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
查看代码
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
using System.Collections;
5![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
6
namespace ObserverDemo
7![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
8![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
10
/// Project alert type.
11
/// </summary>
12
[Flags]
13
public enum ChangeType
14![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
15
workItemChanged = 0x0001,
16
checkedIn = 0x0002,
17
qualityChanged = 0x0004,
18
buildCompleted = 0x0008
19
}
20![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
22
/// Supply a set of rules that every project should apply.
23
/// Of course it is designed for observer pattern.
24
/// </summary>
25
public interface IProjectTemplateStoredInTFS
26![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
27
void SubscribeProjectAlerts(ReceiverBase receiver);
28
void UnsubscribeProjectAlerts(ReceiverBase receiver);
29
void SendProjectAlert();
30
}
31![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
32![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
33
/// Base class for receivers.
34
/// </summary>
35
public abstract class ReceiverBase
36![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
37
protected string _mailContent;
38
protected string _receiverName;
39
protected ChangeType _changeType;
40
protected IProjectTemplateStoredInTFS _projectForUnsubscribe;
41
public ChangeType ProjectChangeType
42![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
43![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _changeType; }
44![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ _changeType = value; }
45
}
46![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
47
public string ReceiverName
48![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
49![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _receiverName; }
50![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{ _receiverName = value; }
51
}
52
public abstract void Update(string content);
53
//Give user a chance to unsubscribe to a project alert.
54
public void Unsubscribe(IProjectTemplateStoredInTFS currentProject)
55![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
56
_projectForUnsubscribe.UnsubscribeProjectAlerts(this);
57
}
58
}
59![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
60![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
61
/// Different user may have different way to display data.
62
/// Every user has to implement this interface.
63
/// </summary>
64
public interface IDisplay
65![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
66
void Display();
67
}
68![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
69![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
70
/// Assume that users in Corpnet are always using OutLook to send and receive emails.
71
/// </summary>
72
public sealed class CorpnetUser : ReceiverBase, IDisplay
73![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
74
public override void Update(string content)
75![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
76
_mailContent = content;
77
Display();
78
}
79![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
80
public void Display()
81![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
82
Console.WriteLine(Environment.NewLine);
83
Console.WriteLine("Welcome to use MS OutLook");
84
Console.WriteLine(_mailContent);
85
}
86
public CorpnetUser(IProjectTemplateStoredInTFS project, string subscriberName, ChangeType changType)
87![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
88
_projectForUnsubscribe = project;
89
_receiverName = subscriberName;
90
_changeType = changType;
91
_projectForUnsubscribe.SubscribeProjectAlerts(this);
92
}
93
}
94![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
95![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
96
/// Assume that userd off Coprnet can use free email service and may
97
/// receive annoying advertisement.
98
/// </summary>
99
public sealed class OffCorpnetUser : ReceiverBase, IDisplay
100![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
101
private string _advertisement;
102
public override void Update(string content)
103![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
104
_mailContent = content;
105
Display();
106
}
107
public OffCorpnetUser(IProjectTemplateStoredInTFS project, ChangeType changType, string subscriberName)
108![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
109
_projectForUnsubscribe = project;
110
_receiverName = subscriberName;
111
_advertisement = "There is no advertisement!";
112
_changeType = changType;
113
_projectForUnsubscribe.SubscribeProjectAlerts(this);
114
}
115
public OffCorpnetUser(IProjectTemplateStoredInTFS project, ChangeType changType, string advertisement, string subscriberName)
116![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
117
_projectForUnsubscribe = project;
118
_receiverName = subscriberName;
119
_advertisement = advertisement;
120
_changeType = changType;
121
_projectForUnsubscribe.SubscribeProjectAlerts(this);
122
}
123
public void Display()
124![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
125
Console.WriteLine(Environment.NewLine);
126
Console.WriteLine("AD: "+_advertisement);
127
Console.WriteLine(_mailContent);
128
}
129
}
130![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
131![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
132
/// Concrete project class.
133
/// </summary>
134
public sealed class MyCurrentProject : IProjectTemplateStoredInTFS
135![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
136
private ArrayList _receivers;
137
private string _author;
138
private string _projectName;
139
ChangeType _changeType;
140
private string _changeHistory;
141![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
142![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
143
public MyCurrentProject(string projectName)
144![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
145
_projectName = projectName;
146
_receivers = new ArrayList();
147
}
148
public void CheckInSourceCode(string author, string fileList)
149![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
150
_author = author;
151
_changeHistory ="The following files :"+ fileList+" were checked in.";
152
_changeType = ChangeType.checkedIn;
153
SendProjectAlert();
154
}
155
public void ChangeWorkItem(string author, string workItem)
156![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
157
_author = author;
158
_changeHistory = "The following workitems are changed: " + workItem;
159
_changeType = ChangeType.workItemChanged;
160
SendProjectAlert();
161
}
162
public void BuildProject(string author)
163![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
164
_author = author;
165
_changeHistory = "Build " + _projectName + " successfully completed!";
166
_changeType = ChangeType.buildCompleted;
167
SendProjectAlert();
168
}
169![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
170
public void MakeQualityChanged()
171![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
172
throw new System.NotImplementedException("It is not implemented for now!");
173
}
174![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
175
public void SubscribeProjectAlerts(ReceiverBase receiver)
176![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
177
if (_receivers.Contains(receiver))
178
Console.WriteLine(receiver.ReceiverName+" has already subscribed to this project alert before!");
179
else
180![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
181
_receivers.Add(receiver);
182
Console.WriteLine("Welcome " + receiver.ReceiverName + "! Thank you for subscribing to project alert!");
183
}
184
}
185![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
186
public void UnsubscribeProjectAlerts(ReceiverBase receiver)
187![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
188
if (_receivers.Contains(receiver))
189![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
190
_receivers.Remove(receiver);
191
Console.WriteLine(receiver.ReceiverName+" has unsubscribed to this project alert!");
192
}
193
}
194![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
195
public void SendProjectAlert()
196![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
197
foreach (ReceiverBase receiver in _receivers)
198![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
199![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
200
StringBuilder sb = new StringBuilder("************************************************");
201
sb.Append(Environment.NewLine);
202
sb.Append("Hi " + receiver.ReceiverName + ",");
203
sb.Append(Environment.NewLine);
204
sb.Append(_changeHistory);
205
sb.Append(Environment.NewLine);
206
sb.Append("Summary:");
207
sb.Append(Environment.NewLine);
208
sb.Append("Team Project: " + _projectName);
209
sb.Append(Environment.NewLine);
210
sb.Append("Author: " + _author);
211
sb.Append(Environment.NewLine);
212
sb.Append("Time: " + DateTime.Now.ToString());
213
sb.Append(Environment.NewLine);
214
sb.Append("![](https://www.cnblogs.com/Images/dot.gif)
..");
215
sb.Append(Environment.NewLine);
216
sb.Append("Provided by Microsoft Visual Studio® 2005 Team System");
217
sb.Append(Environment.NewLine);
218
sb.Append("************************************************");
219
sb.Append(Environment.NewLine);
220
//Who has subscribed current type of project alert?
221
if (receiver.ProjectChangeType.ToString().IndexOf(_changeType.ToString()) >= 0)
222
receiver.Update(sb.ToString());
223
}
224![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
225
}
226![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
227![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
228
}
229![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
230
class Program
231![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
232
static void Main(string[] args)
233![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
234
MyCurrentProject myproject = new MyCurrentProject("HugeProject");
235
OffCorpnetUser offCorpnetUser1 = new OffCorpnetUser(myproject, ChangeType.buildCompleted | ChangeType.workItemChanged, "Welcome to use this free email service, click here to win award!", "XXX");
236
CorpnetUser corpnetUser1 = new CorpnetUser(myproject, "MM", ChangeType.checkedIn | ChangeType.buildCompleted);
237
myproject.ChangeWorkItem("zhanqiangz", "WorkItem110 has been changed!");
238
myproject.CheckInSourceCode("zhanqiangz", "global.asmx,web.config");
239
myproject.BuildProject("zhanqiangz");
240
corpnetUser1.Unsubscribe(myproject);
241
myproject.CheckInSourceCode("zhanqiangz", "global.asmx,web.config");
242
Console.ReadKey();
243![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
244
}
245
}
246
}
247![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
运行结果图:
本例引出的面向对象原则:
尽量将交互的对象设计为松散耦合(strive for loosely coupled designs between objects that interact)在本例中TFS完全不需要知道订阅者是谁,不管你是Manager,PM,还是只是普通的SDE,你只要使用project alert订阅了你感兴趣的东西,都会把相关的信息发送给你。
代码下载:
ObserverDemo.zip后续:
生活中这样的例子很多,比如手机短信订阅,网上购物,订阅报纸,婚姻介绍所,通过猎头找工作等等。我写这些东西主要是为了巩固自己对模式的理解,例子中错误在所难免,虽然我写的是head first读书笔记,但是我深信自己没有能力把文章写的那么生动有趣,也没有精力去迎合别人的阅读兴趣;写出来共享资源是目的之二,希望能给像我一样对模式理解不深的朋友提供一点信息,仅此而已。