Head First Design patterns笔记-Observer Patterns (从TFS的Project alerts功能看观察者模式)...

本文介绍如何利用观察者模式在Team Foundation Server (TFS) 中实现项目警报功能,允许用户订阅并接收关于项目状态变更的通知邮件。

定义: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自动生成的类图






实例代码

ContractedBlock.gif ExpandedBlockStart.gif 查看代码
  1None.gifusing System;
  2None.gifusing System.Collections.Generic;
  3None.gifusing System.Text;
  4None.gifusing System.Collections;
  5None.gif
  6None.gifnamespace ObserverDemo
  7ExpandedBlockStart.gifContractedBlock.gifdot.gif{
  8InBlock.gif
  9ExpandedSubBlockStart.gifContractedSubBlock.gif   /**//// <summary>
 10InBlock.gif   /// Project alert type.
 11ExpandedSubBlockEnd.gif   /// </summary>

 12InBlock.gif    [Flags]
 13InBlock.gif    public enum ChangeType
 14ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 15InBlock.gif        workItemChanged = 0x0001,
 16InBlock.gif        checkedIn = 0x0002,
 17InBlock.gif        qualityChanged = 0x0004,
 18InBlock.gif        buildCompleted = 0x0008
 19ExpandedSubBlockEnd.gif    }

 20InBlock.gif
 21ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
 22InBlock.gif    /// Supply a set of rules that every project should apply.
 23InBlock.gif    /// Of course it is designed for observer pattern.
 24ExpandedSubBlockEnd.gif    /// </summary>

 25InBlock.gif    public interface IProjectTemplateStoredInTFS
 26ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 27InBlock.gif        void SubscribeProjectAlerts(ReceiverBase receiver);
 28InBlock.gif        void UnsubscribeProjectAlerts(ReceiverBase receiver);
 29InBlock.gif        void SendProjectAlert();
 30ExpandedSubBlockEnd.gif    }

 31InBlock.gif
 32ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
 33InBlock.gif    /// Base class for receivers.
 34ExpandedSubBlockEnd.gif    /// </summary>

 35InBlock.gif    public abstract class ReceiverBase
 36ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 37InBlock.gif        protected string _mailContent;
 38InBlock.gif        protected string _receiverName;
 39InBlock.gif        protected ChangeType _changeType;
 40InBlock.gif        protected IProjectTemplateStoredInTFS _projectForUnsubscribe;
 41InBlock.gif        public ChangeType ProjectChangeType
 42ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 43ExpandedSubBlockStart.gifContractedSubBlock.gif            get dot.gifreturn _changeType; }
 44ExpandedSubBlockStart.gifContractedSubBlock.gif            set dot.gif{ _changeType = value; }
 45ExpandedSubBlockEnd.gif        }

 46InBlock.gif
 47InBlock.gif        public string ReceiverName
 48ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 49ExpandedSubBlockStart.gifContractedSubBlock.gif            get dot.gifreturn _receiverName; }
 50ExpandedSubBlockStart.gifContractedSubBlock.gif            set dot.gif{ _receiverName = value; }
 51ExpandedSubBlockEnd.gif        }

 52InBlock.gif        public abstract void Update(string content);
 53InBlock.gif        //Give user a chance to unsubscribe to a project alert.
 54InBlock.gif        public void Unsubscribe(IProjectTemplateStoredInTFS currentProject)
 55ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 56InBlock.gif            _projectForUnsubscribe.UnsubscribeProjectAlerts(this);
 57ExpandedSubBlockEnd.gif        }

 58ExpandedSubBlockEnd.gif    }

 59InBlock.gif
 60ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
 61InBlock.gif    /// Different user may have different way to display data.
 62InBlock.gif    /// Every user has to implement this interface.
 63ExpandedSubBlockEnd.gif    /// </summary>

 64InBlock.gif    public interface IDisplay
 65ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 66InBlock.gif        void Display();
 67ExpandedSubBlockEnd.gif    }

 68InBlock.gif
 69ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
 70InBlock.gif    /// Assume that users in Corpnet are always using OutLook to send and receive emails.
 71ExpandedSubBlockEnd.gif    /// </summary>

 72InBlock.gif    public sealed class CorpnetUser : ReceiverBase, IDisplay
 73ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 74InBlock.gif        public override void Update(string content)
 75ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 76InBlock.gif            _mailContent = content;
 77InBlock.gif            Display();
 78ExpandedSubBlockEnd.gif        }

 79InBlock.gif
 80InBlock.gif        public void Display()
 81ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 82InBlock.gif            Console.WriteLine(Environment.NewLine);
 83InBlock.gif            Console.WriteLine("Welcome to use MS OutLook");
 84InBlock.gif            Console.WriteLine(_mailContent);
 85ExpandedSubBlockEnd.gif        }

 86InBlock.gif        public CorpnetUser(IProjectTemplateStoredInTFS project, string subscriberName, ChangeType changType)
 87ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 88InBlock.gif            _projectForUnsubscribe = project;
 89InBlock.gif            _receiverName = subscriberName;
 90InBlock.gif            _changeType = changType;
 91InBlock.gif            _projectForUnsubscribe.SubscribeProjectAlerts(this);
 92ExpandedSubBlockEnd.gif        }

 93ExpandedSubBlockEnd.gif    }

 94InBlock.gif
 95ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
 96InBlock.gif    /// Assume that userd off Coprnet can use free email service and may
 97InBlock.gif    /// receive annoying advertisement.
 98ExpandedSubBlockEnd.gif    /// </summary>

 99InBlock.gif    public sealed class OffCorpnetUser : ReceiverBase, IDisplay
100ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
101InBlock.gif        private string _advertisement;
102InBlock.gif        public override void Update(string content)
103ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
104InBlock.gif            _mailContent = content;
105InBlock.gif            Display();
106ExpandedSubBlockEnd.gif        }

107InBlock.gif        public OffCorpnetUser(IProjectTemplateStoredInTFS project, ChangeType changType, string subscriberName)
108ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
109InBlock.gif            _projectForUnsubscribe = project;
110InBlock.gif            _receiverName = subscriberName;
111InBlock.gif            _advertisement = "There is no advertisement!";
112InBlock.gif            _changeType = changType;
113InBlock.gif            _projectForUnsubscribe.SubscribeProjectAlerts(this);
114ExpandedSubBlockEnd.gif        }

115InBlock.gif        public OffCorpnetUser(IProjectTemplateStoredInTFS project, ChangeType changType, string advertisement, string subscriberName)
116ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
117InBlock.gif            _projectForUnsubscribe = project;
118InBlock.gif            _receiverName = subscriberName;
119InBlock.gif            _advertisement = advertisement;
120InBlock.gif            _changeType = changType;
121InBlock.gif            _projectForUnsubscribe.SubscribeProjectAlerts(this);
122ExpandedSubBlockEnd.gif        }

123InBlock.gif        public void Display()
124ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
125InBlock.gif            Console.WriteLine(Environment.NewLine);
126InBlock.gif            Console.WriteLine("AD: "+_advertisement);
127InBlock.gif            Console.WriteLine(_mailContent);
128ExpandedSubBlockEnd.gif        }

129ExpandedSubBlockEnd.gif    }

130InBlock.gif
131ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
132InBlock.gif    /// Concrete project class.
133ExpandedSubBlockEnd.gif    /// </summary>

134InBlock.gif    public sealed class MyCurrentProject : IProjectTemplateStoredInTFS
135ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
136InBlock.gif        private ArrayList _receivers;
137InBlock.gif        private string _author;
138InBlock.gif        private string _projectName;
139InBlock.gif        ChangeType _changeType;
140InBlock.gif        private string _changeHistory;
141InBlock.gif
142InBlock.gif
143InBlock.gif        public MyCurrentProject(string projectName)
144ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
145InBlock.gif            _projectName = projectName;
146InBlock.gif            _receivers = new ArrayList();
147ExpandedSubBlockEnd.gif        }

148InBlock.gif        public void CheckInSourceCode(string author, string fileList)
149ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
150InBlock.gif            _author = author;
151InBlock.gif            _changeHistory ="The following files :"+ fileList+" were checked in.";
152InBlock.gif            _changeType = ChangeType.checkedIn;
153InBlock.gif            SendProjectAlert();
154ExpandedSubBlockEnd.gif        }

155InBlock.gif        public void ChangeWorkItem(string author, string workItem)
156ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
157InBlock.gif            _author = author;
158InBlock.gif            _changeHistory = "The following workitems are changed: " + workItem;
159InBlock.gif            _changeType = ChangeType.workItemChanged;
160InBlock.gif            SendProjectAlert();
161ExpandedSubBlockEnd.gif        }

162InBlock.gif        public void BuildProject(string author)
163ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
164InBlock.gif            _author = author;
165InBlock.gif            _changeHistory = "Build " + _projectName + " successfully completed!";
166InBlock.gif            _changeType = ChangeType.buildCompleted;
167InBlock.gif            SendProjectAlert();
168ExpandedSubBlockEnd.gif        }

169InBlock.gif
170InBlock.gif        public void MakeQualityChanged()
171ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
172InBlock.gif            throw new System.NotImplementedException("It is not implemented for now!");
173ExpandedSubBlockEnd.gif        }

174InBlock.gif
175InBlock.gif        public void SubscribeProjectAlerts(ReceiverBase receiver)
176ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
177InBlock.gif            if (_receivers.Contains(receiver))
178InBlock.gif                Console.WriteLine(receiver.ReceiverName+" has already subscribed to this project alert before!");
179InBlock.gif            else
180ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
181InBlock.gif                _receivers.Add(receiver);
182InBlock.gif                Console.WriteLine("Welcome " + receiver.ReceiverName + "!  Thank you for subscribing to project alert!");
183ExpandedSubBlockEnd.gif            }

184ExpandedSubBlockEnd.gif        }

185InBlock.gif
186InBlock.gif        public void UnsubscribeProjectAlerts(ReceiverBase receiver)
187ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
188InBlock.gif            if (_receivers.Contains(receiver))
189ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
190InBlock.gif                _receivers.Remove(receiver);
191InBlock.gif                Console.WriteLine(receiver.ReceiverName+" has unsubscribed to this project alert!");
192ExpandedSubBlockEnd.gif            }

193ExpandedSubBlockEnd.gif        }

194InBlock.gif
195InBlock.gif        public void SendProjectAlert()
196ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
197InBlock.gif            foreach (ReceiverBase receiver in _receivers)
198ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
199InBlock.gif
200InBlock.gif                StringBuilder sb = new StringBuilder("************************************************");
201InBlock.gif                sb.Append(Environment.NewLine);
202InBlock.gif                sb.Append("Hi " + receiver.ReceiverName + ",");
203InBlock.gif                sb.Append(Environment.NewLine);
204InBlock.gif                sb.Append(_changeHistory);
205InBlock.gif                sb.Append(Environment.NewLine);
206InBlock.gif                sb.Append("Summary:");
207InBlock.gif                sb.Append(Environment.NewLine);
208InBlock.gif                sb.Append("Team Project: " + _projectName);
209InBlock.gif                sb.Append(Environment.NewLine);
210InBlock.gif                sb.Append("Author: " + _author);
211InBlock.gif                sb.Append(Environment.NewLine);
212InBlock.gif                sb.Append("Time: " + DateTime.Now.ToString());
213InBlock.gif                sb.Append(Environment.NewLine);
214InBlock.gif                sb.Append("dot.gifdot.gif..");
215InBlock.gif                sb.Append(Environment.NewLine);
216InBlock.gif                sb.Append("Provided by Microsoft Visual Studio® 2005 Team System");
217InBlock.gif                sb.Append(Environment.NewLine);
218InBlock.gif                sb.Append("************************************************");
219InBlock.gif                sb.Append(Environment.NewLine);
220InBlock.gif                //Who has subscribed current type of project alert?
221InBlock.gif                if (receiver.ProjectChangeType.ToString().IndexOf(_changeType.ToString()) >= 0)
222InBlock.gif                    receiver.Update(sb.ToString());
223ExpandedSubBlockEnd.gif            }

224InBlock.gif
225ExpandedSubBlockEnd.gif        }

226InBlock.gif
227InBlock.gif
228ExpandedSubBlockEnd.gif    }

229InBlock.gif
230InBlock.gif    class Program
231ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
232InBlock.gif        static void Main(string[] args)
233ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
234InBlock.gif            MyCurrentProject myproject = new MyCurrentProject("HugeProject");
235InBlock.gif            OffCorpnetUser offCorpnetUser1 = new OffCorpnetUser(myproject, ChangeType.buildCompleted | ChangeType.workItemChanged, "Welcome to use this free email service, click here to win award!""XXX");
236InBlock.gif            CorpnetUser corpnetUser1 = new CorpnetUser(myproject, "MM", ChangeType.checkedIn | ChangeType.buildCompleted);
237InBlock.gif            myproject.ChangeWorkItem("zhanqiangz""WorkItem110 has been changed!");
238InBlock.gif            myproject.CheckInSourceCode("zhanqiangz""global.asmx,web.config");
239InBlock.gif            myproject.BuildProject("zhanqiangz");
240InBlock.gif            corpnetUser1.Unsubscribe(myproject);
241InBlock.gif            myproject.CheckInSourceCode("zhanqiangz""global.asmx,web.config");
242InBlock.gif            Console.ReadKey();
243InBlock.gif
244ExpandedSubBlockEnd.gif        }

245ExpandedSubBlockEnd.gif    }

246ExpandedBlockEnd.gif}

247None.gif

运行结果图


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

代码下载
ObserverDemo.zip

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

转载于:https://www.cnblogs.com/netboy/archive/2007/05/01/733906.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值