Head First Design patterns笔记-Observer Patterns (从TFS的Project alerts功能看观察者模式)
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就可以了。
VS自动生成的类图:
实例代码:
1
using System;2
using System.Collections.Generic;3
using System.Text;4
using System.Collections;5

6
namespace ObserverDemo7


{8

9

/**//// <summary>10
/// Project alert type.11
/// </summary>12
[Flags]13
public enum ChangeType14

{15
workItemChanged = 0x0001,16
checkedIn = 0x0002,17
qualityChanged = 0x0004,18
buildCompleted = 0x000819
}20

21

/**//// <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 IProjectTemplateStoredInTFS26

{27
void SubscribeProjectAlerts(ReceiverBase receiver);28
void UnsubscribeProjectAlerts(ReceiverBase receiver);29
void SendProjectAlert();30
}31

32

/**//// <summary>33
/// Base class for receivers.34
/// </summary>35
public abstract class ReceiverBase36

{37
protected string _mailContent;38
protected string _receiverName;39
protected ChangeType _changeType;40
protected IProjectTemplateStoredInTFS _projectForUnsubscribe;41
public ChangeType ProjectChangeType42

{43

get
{ return _changeType; }44

set
{ _changeType = value; }45
}46

47
public string ReceiverName48

{49

get
{ return _receiverName; }50

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

{56
_projectForUnsubscribe.UnsubscribeProjectAlerts(this);57
}58
}59

60

/**//// <summary>61
/// Different user may have different way to display data.62
/// Every user has to implement this interface.63
/// </summary>64
public interface IDisplay65

{66
void Display();67
}68

69

/**//// <summary>70
/// Assume that users in Corpnet are always using OutLook to send and receive emails.71
/// </summary>72
public sealed class CorpnetUser : ReceiverBase, IDisplay73

{74
public override void Update(string content)75

{76
_mailContent = content;77
Display();78
}79

80
public void Display()81

{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

{88
_projectForUnsubscribe = project;89
_receiverName = subscriberName;90
_changeType = changType;91
_projectForUnsubscribe.SubscribeProjectAlerts(this);92
}93
}94

95

/**//// <summary>96
/// Assume that userd off Coprnet can use free email service and may97
/// receive annoying advertisement.98
/// </summary>99
public sealed class OffCorpnetUser : ReceiverBase, IDisplay100

{101
private string _advertisement;102
public override void Update(string content)103

{104
_mailContent = content;105
Display();106
}107
public OffCorpnetUser(IProjectTemplateStoredInTFS project, ChangeType changType, string subscriberName)108

{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

{117
_projectForUnsubscribe = project;118
_receiverName = subscriberName;119
_advertisement = advertisement;120
_changeType = changType;121
_projectForUnsubscribe.SubscribeProjectAlerts(this);122
}123
public void Display()124

{125
Console.WriteLine(Environment.NewLine);126
Console.WriteLine("AD: "+_advertisement);127
Console.WriteLine(_mailContent);128
}129
}130

131

/**//// <summary>132
/// Concrete project class.133
/// </summary>134
public sealed class MyCurrentProject : IProjectTemplateStoredInTFS135

{136
private ArrayList _receivers;137
private string _author;138
private string _projectName;139
ChangeType _changeType;140
private string _changeHistory;141

142

143
public MyCurrentProject(string projectName)144

{145
_projectName = projectName;146
_receivers = new ArrayList();147
}148
public void CheckInSourceCode(string author, string fileList)149

{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

{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

{164
_author = author;165
_changeHistory = "Build " + _projectName + " successfully completed!";166
_changeType = ChangeType.buildCompleted;167
SendProjectAlert();168
}169

170
public void MakeQualityChanged()171

{172
throw new System.NotImplementedException("It is not implemented for now!");173
}174

175
public void SubscribeProjectAlerts(ReceiverBase receiver)176

{177
if (_receivers.Contains(receiver))178
Console.WriteLine(receiver.ReceiverName+" has already subscribed to this project alert before!");179
else180

{181
_receivers.Add(receiver);182
Console.WriteLine("Welcome " + receiver.ReceiverName + "! Thank you for subscribing to project alert!");183
}184
}185

186
public void UnsubscribeProjectAlerts(ReceiverBase receiver)187

{188
if (_receivers.Contains(receiver))189

{190
_receivers.Remove(receiver);191
Console.WriteLine(receiver.ReceiverName+" has unsubscribed to this project alert!");192
}193
}194

195
public void SendProjectAlert()196

{197
foreach (ReceiverBase receiver in _receivers)198

{199

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("
..");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

225
}226

227

228
}229

230
class Program231

{232
static void Main(string[] args)233

{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

244
}245
}246
}247

运行结果图:
本例引出的面向对象原则:
尽量将交互的对象设计为松散耦合(strive for loosely coupled designs between objects that interact)
在本例中TFS完全不需要知道订阅者是谁,不管你是Manager,PM,还是只是普通的SDE,你只要使用project alert订阅了你感兴趣的东西,都会把相关的信息发送给你。
代码下载:
ObserverDemo.zip
后续:
生活中这样的例子很多,比如手机短信订阅,网上购物,订阅报纸,婚姻介绍所,通过猎头找工作等等。我写这些东西主要是为了巩固自己对模式的理解,例子中错误在所难免,虽然我写的是head first读书笔记,但是我深信自己没有能力把文章写的那么生动有趣,也没有精力去迎合别人的阅读兴趣;写出来共享资源是目的之二,希望能给像我一样对模式理解不深的朋友提供一点信息,仅此而已。

浙公网安备 33010602011771号