在觀察者模式中有2個要素:一個是被觀察物件,另一個是觀察者。但被觀察物件的狀態發生改變會通知觀察者。
舉例:把訂閱報紙的人看作是觀察者,把報紙看作被觀察物件。每當有新的新聞就要通知訂閱報紙的人。本篇分別用實現介面和使用委託事件的方式來實現。
□ 通過實現介面實現
觀察者介面,把接收到的新聞顯示出來。
public interface IObserver{void Update(string news);}
被觀察物件介面,提供3個方法:註冊觀察者,取消觀察者,通知觀察者。
public interface ISubject{void RegisteerObserver(IObserver o);
void RemoveObserver(IObserver o);
void NotifyObservers();
}
被觀察物件實現類,維護著一個觀察者介面的集合,對觀察者的註冊和取消實際上是往這個集合新增或移除資料。
public class NewsPublisher : ISubject{private List<IObserver> observers = new List<IObserver>();private List<string> newsList = new List<string>();public void RegisteerObserver(IObserver o){observers.Add(o);}public void RemoveObserver(IObserver o){observers.Remove(o);}public void NotifyObservers(){foreach (IObserver o in observers){o.Update(newsList[newsList.Count - 1]);}}public void PublishNews(string news){newsList.Add(news);NotifyObservers();}}
另外,被觀察物件實現類還維護著一個string型別的新聞集合,每當釋出新聞,就往這個集合裡新增資料,並通知所有的註冊觀察者。
觀察者的實現類。
public class NewsSubscriber : IObserver{public void Update(string news){Console.WriteLine("收到通知了");
Console.WriteLine(news);}}
客戶端,被觀察物件註冊觀察者並觸發動作。
class Program
{static void Main(string[] args){NewsPublisher publisher = new NewsPublisher();
NewsSubscriber subscriber = new NewsSubscriber();
publisher.RegisteerObserver(subscriber);publisher.PublishNews("看報,看報,快來看報~");
Console.ReadKey();}}
□ 使用委託事件實現
看到以上的做法,委託和事件這對好朋友就笑了。註冊、取消觀察者還得用2個方法,那讓我們情何以堪?我們這樣做:
觀察者類只負責對收到的新聞顯示。
public class NewsSubscriber{public void Update(string news){Console.WriteLine("收到新聞了~");
Console.WriteLine(news);}}
被觀察物件類用到了委託和事件。
public class NewsPublisher{private readonly List<string> newsList = new List<string>();public delegate void NotifyOvserversHandler(string news);public event NotifyOvserversHandler newsPublished;public void PublishNews(string news){newsList.Add(news);newsPublished(newsList[newsList.Count - 1]);}}
以上,委託宣告瞭方法的定義,接收一個string型別引數,返回void。事件負責對符合委託定義的、觀察者方法的註冊和取消。
在客戶端使用事件對方法進行註冊。
class Program
{static void Main(string[] args){NewsPublisher publisher = new NewsPublisher();
NewsSubscriber subscriber = new NewsSubscriber();
publisher.newsPublished += subscriber.Update;publisher.PublishNews("現在是看報時間~");
Console.ReadKey();}}
與通過介面實現不同,使用事件註冊的是觀察者的方法,而不是觀察者本身。
總結:無論通過介面實現,還是使用委託和事件,觀察者模式的要素是不變的:被觀察物件,觀察者,被觀察者提供註冊、取消觀察者或觀察者方法,通過被觀察物件的某個方法觸發、通知觀察者。