咨詢電話:023-6276-4481
熱門文章
電 話:023-6276-4481
郵箱:broiling@qq.com
地址:重慶市南岸區(qū)亞太商谷6幢25-2
員工上班期間,很多同事會(huì)趁老板不在偷偷看股票,但是又害怕老板突然回來(lái)出現(xiàn)在身后,而被逮個(gè)正著。于是乎。公司同事開(kāi)始和前臺(tái)小美眉不斷獻(xiàn)殷勤,希望前臺(tái)能在老板會(huì)公司的時(shí)候打個(gè)電話到部門辦公室,這樣大家就都知道老板回來(lái)了,可以馬上把股票界面關(guān)掉。
其實(shí)像上面這個(gè)場(chǎng)景就是一個(gè)典型的觀察者模式案例。我們先把它寫(xiě)成程序。
前臺(tái)就相當(dāng)于觀察者模式當(dāng)中的主題,它負(fù)責(zé)給所有觀察者也就是公司同事發(fā)送老板回來(lái)了的消息。
首先定義一個(gè)主題接口
//主題接口 interface ISubject { //增加觀察者,公司同事 void Attach(Observer observer); //移除觀察者 void Detach(Observer observer); //消息(如果老板回來(lái)了,馬上向所有觀察者也就是公司同事發(fā)送消息) void Notify(); //發(fā)布狀態(tài)(老板是否回來(lái)的狀態(tài)) string SubjectState { get; set; } }
然后定義一個(gè)具體的主題,這里就是前臺(tái),讓它繼承于主題接口
//具體主題 class Secretary : ISubject { //觀察者列表 private IList<Observer> observers = new List<Observer>(); private string action; public void Attach(Observer observer) { observers.Add(observer); } public void Detach(Observer observer) { observers.Remove(observer); } //遍歷所有觀察者,給每一個(gè)觀察者發(fā)送消息 public void Notify() { foreach (Observer o in observers) { o.Update(); } } public string SubjectState { get { return action; } set { action = value; } } }
接著定義抽象觀察者
//抽象觀察者 abstract class Observer { //同事姓名 protected string name; //觀察的主題 protected ISubject sub; public Observer(string name, ISubject sub) { this.name = name; this.sub = sub; } //收到消息后的更新行為 public abstract void Update(); }
這里之所以要定義抽象觀察者,是為了提高程序的擴(kuò)展性,因?yàn)椴灰欢ㄋ型露伎垂善保热邕€有同事看NBA的,那只要讓他們都繼承與這個(gè)抽象類就好了
//看股票的同事類 class StockObserver : Observer { public StockObserver(string name, ISubject sub) :base(name, sub ) { } public override void Update() { Console.WriteLine("{0},{1},closeStock",sub.SubjectState,name); } } //看NBA的同事類 class NBAObserver : Observer { public NBAObserver(string name, ISubject sub) : base(name, sub) { } public override void Update() { Console.WriteLine("{0},{1},closeNBA", sub.SubjectState, name); } }
客戶端
static void Main(string[] args) { Secretary sec = new Secretary(); sec.Attach(new StockObserver("allen",sec)); sec.Attach(new NBAObserver("kobe", sec)); sec.SubjectState = "boss is back"; sec.Notify(); }
觀察者模式所做的工作其實(shí)就是在解除耦合。讓耦合的雙方都依賴于抽象,而不是依賴于具體。從而使得各自的變化都不會(huì)影響另一邊的變化。
在具體應(yīng)用中,不大會(huì)出現(xiàn)所有的觀察者都是具備同一行為(關(guān)閉股票或者NBA界面),可能不同的觀察者會(huì)有完全不同的行為,所以這個(gè)時(shí)候我們就會(huì)通過(guò)委托來(lái)實(shí)現(xiàn)觀察者模式
修改前臺(tái)主題類
//定義一個(gè)委托delegate void EventHandler(); class Secretary : ISubject { //聲明一個(gè)事件,類型為委托EventHandler public event EventHandler Update; private string action; public void Notify() { Update(); } public string SubjectState { get { return action; } set { action = value; } } }
股票同事類中,可以用自己定義的行為
class StockObserver : Observer { public StockObserver(string name, ISubject sub) :base(name, sub ) { } //自己定義的方法 public void CloseStockMarket() { Console.WriteLine("{0},{1},closeStock",sub.SubjectState,name); } }
NBA同事類也一樣
class NBAObserver : Observer { public NBAObserver(string name, ISubject sub) : base(name, sub) { } public void CloseNBADirectSeeding() { Console.WriteLine("{0},{1},closeNBA", sub.SubjectState, name); } }
客戶端
static void Main(string[] args) { Secretary sec = new Secretary(); StockObserver stock = new StockObserver("allen",sec); NBAObserver nba = new NBAObserver("kobe",sec); sec.SubjectState = "back"; //將各自的行為添加到事件中 sec.Update += new EventHandler(stock.CloseStockMarket); sec.Update += new EventHandler(nba.CloseNBADirectSeeding); sec.Notify(); }
1、 對(duì)一個(gè)對(duì)象狀態(tài)的更新,需要其他對(duì)象同步更新,而且其他對(duì)象的數(shù)量動(dòng)態(tài)可變。
2、 對(duì)象僅需要將自己的更新通知給其他對(duì)象而不需要知道其他對(duì)象的細(xì)節(jié)。
1、 Subject和Observer之間是松偶合的,分別可以各自獨(dú)立改變。
2、 Subject在發(fā)送廣播通知的時(shí)候,無(wú)須指定具體的Observer,Observer可以自己決定是否要訂閱Subject的通知。
3、 遵守大部分GRASP原則和常用設(shè)計(jì)原則,高內(nèi)聚、低偶合。