Head First Design patterns笔记-Observer Patterns (从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就可以了。
Head First Design patterns笔记-Observer Patterns (从TFS的Project alerts功能看观察者模式)_第1张图片

VS自动生成的类图
Head First Design patterns笔记-Observer Patterns (从TFS的Project alerts功能看观察者模式)_第2张图片

Head First Design patterns笔记-Observer Patterns (从TFS的Project alerts功能看观察者模式)_第3张图片



实例代码

查看代码
  1using System;
  2using System.Collections.Generic;
  3using System.Text;
  4using System.Collections;
  5
  6namespace ObserverDemo
  7{
  8
  9   /**//// <summary>
 10   /// Project alert type.
 11   /// </summary>

 12    [Flags]
 13    public enum ChangeType
 14    {
 15        workItemChanged = 0x0001,
 16        checkedIn = 0x0002,
 17        qualityChanged = 0x0004,
 18        buildCompleted = 0x0008
 19    }

 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 IProjectTemplateStoredInTFS
 26    {
 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 ReceiverBase
 36    {
 37        protected string _mailContent;
 38        protected string _receiverName;
 39        protected ChangeType _changeType;
 40        protected IProjectTemplateStoredInTFS _projectForUnsubscribe;
 41        public ChangeType ProjectChangeType
 42        {
 43            get return _changeType; }
 44            set { _changeType = value; }
 45        }

 46
 47        public string ReceiverName
 48        {
 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 IDisplay
 65    {
 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, IDisplay
 73    {
 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 may
 97    /// receive annoying advertisement.
 98    /// </summary>

 99    public sealed class OffCorpnetUser : ReceiverBase, IDisplay
100    {
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 : IProjectTemplateStoredInTFS
135    {
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            else
180            {
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 Program
231    {
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

运行结果图
Head First Design patterns笔记-Observer Patterns (从TFS的Project alerts功能看观察者模式)_第4张图片

本例引出的面向对象原则
尽量将交互的对象设计为松散耦合(strive for loosely coupled designs between objects that interact)
在本例中TFS完全不需要知道订阅者是谁,不管你是Manager,PM,还是只是普通的SDE,你只要使用project alert订阅了你感兴趣的东西,都会把相关的信息发送给你。

代码下载
ObserverDemo.zip

后续
生活中这样的例子很多,比如手机短信订阅,网上购物,订阅报纸,婚姻介绍所,通过猎头找工作等等。我写这些东西主要是为了巩固自己对模式的理解,例子中错误在所难免,虽然我写的是head first读书笔记,但是我深信自己没有能力把文章写的那么生动有趣,也没有精力去迎合别人的阅读兴趣;写出来共享资源是目的之二,希望能给像我一样对模式理解不深的朋友提供一点信息,仅此而已。

你可能感兴趣的:(Head First Design patterns笔记-Observer Patterns (从TFS的Project alerts功能看观察者模式))