C# 設計形式系列教程-不雅察者形式。本站提示廣大學習愛好者:(C# 設計形式系列教程-不雅察者形式)文章只能為提供參考,不一定能成為您想要的結果。以下是C# 設計形式系列教程-不雅察者形式正文
1. 概述
有時被稱作宣布/定閱形式,不雅察者形式界說了一種一對多的依附關系,讓多個不雅察者對象同時監聽某一個主題對象。這個主題對象在狀況產生變更時,會告訴一切不雅察者對象,使它們可以或許主動更新本身。
2. 處理的成績
將一個體系朋分成一個一些類互相協作的類有一個欠好的反作用,那就是須要保護相干對象間的分歧性。我們不願望為了保持分歧性而使各類慎密耦合,如許會給保護、擴大和重用都帶來未便。不雅察者就是處理這類的耦合關系的。
3. 形式中的腳色
3.1 籠統主題(Subject):它把一切不雅察者對象的援用保留到一個集合裡,每一個主題都可以有任何數目的不雅察者。籠統主題供給一個接口,可以增長和刪除不雅察者對象。
3.2 詳細主題(ConcreteSubject):將有關狀況存入詳細不雅察者對象;在詳細主題外部狀況轉變時,給一切掛號過的不雅察者收回告訴。
3.3 籠統不雅察者(Observer):為一切的詳細不雅察者界說一個接口,在獲得主題告訴時更新本身。
3.4 詳細不雅察者(ConcreteObserver):完成籠統不雅察者腳色所請求的更新接口,以便使自己的狀況與主題狀況調和。
4. 形式解讀
4.1 不雅察者形式的類圖
4.2 不雅察者形式的代碼
/// <summary> /// 籠統主題類 /// </summary> public abstract class Subject { private IList<Observer> observers = new List<Observer>(); /// <summary> /// 增長不雅察者 /// </summary> /// <param name="observer"></param> public void Attach(Observer observer) { observers.Add(observer); } /// <summary> /// 移除不雅察者 /// </summary> /// <param name="observer"></param> public void Detach(Observer observer) { observers.Remove(observer); } /// <summary> /// 向不雅察者(們)收回告訴 /// </summary> public void Notify() { foreach (Observer o in observers) { o.Update(); } } } /// <summary> /// 籠統不雅察者類,為一切詳細不雅察者界說一個接口,在獲得告訴時更新本身 /// </summary> public abstract class Observer { public abstract void Update(); } /// <summary> /// 詳細不雅察者或詳細告訴者,將有關狀況存入詳細不雅察者對象;在詳細主題的外部狀況轉變時,給一切掛號過的不雅察者收回告訴。詳細主題腳色平日用一個詳細子類完成。 /// </summary> public class ConcreteSubject : Subject { private string subjectState; /// <summary> /// 詳細不雅察者的狀況 /// </summary> public string SubjectState { get { return subjectState; } set { subjectState = value; } } } /// <summary> /// 詳細不雅察者,完成籠統不雅察者腳色所請求的更新接口,已經是自己狀況與主題狀況相調和 /// </summary> public class ConcreteObserver : Observer { private string observerState; private string name; private ConcreteSubject subject; /// <summary> /// 詳細不雅察者用一個詳細主題來完成 /// </summary> public ConcreteSubject Subject { get { return subject; } set { subject = value; } } public ConcreteObserver(ConcreteSubject subject, string name) { this.subject = subject; this.name = name; } /// <summary> /// 完成籠統不雅察者中的更新操作 /// </summary> public override void Update() { observerState = subject.SubjectState; Console.WriteLine("The observer's state of {0} is {1}", name, observerState); } }
4.3 客戶端代碼
class Program { static void Main(string[] args) { // 詳細主題腳色平日器具體自來來完成 ConcreteSubject subject = new ConcreteSubject(); subject.Attach(new ConcreteObserver(subject, "Observer A")); subject.Attach(new ConcreteObserver(subject, "Observer B")); subject.Attach(new ConcreteObserver(subject, "Observer C")); subject.SubjectState = "Ready"; subject.Notify(); Console.Read(); } }
運轉成果
5. 形式總結
5.1 長處
5.1.1 不雅察者形式消除了主題和詳細不雅察者的耦合,讓耦合的兩邊都依附於籠統,而不是依附詳細。從而使得各自的變更都不會影響另外一邊的變更。
5.2 缺陷
5.2.1 依附關系並未完整消除,籠統告訴者照舊依附籠統的不雅察者。
5.3 實用場景
5.3.1 當一個對象的轉變須要給變其它對象時,並且它不曉得詳細有若干個對象有待轉變時。
5.3.2 一個籠統某型有兩個方面,當個中一個方面依附於另外一個方面,這時候用不雅察者形式可以將這二者封裝在自力的對象中使它們各自自力地轉變和復用。
6. 形式引伸,運用C#中的事宜拜托來完全消除告訴者和不雅察者之間的耦合。
6.1 關於拜托的界說:拜托是一種援用辦法的類型。一旦為拜托分派了辦法,拜托將與該辦法有雷同的行動。拜托辦法可以像其它任何辦法一樣,具有參數和前往值。拜托可以看做是對函數(辦法)的的籠統,是函數的“類”,拜托的實例代表一個(或多個)詳細的函數,它可所以多播的。
6.2 關於事宜:事宜基於拜托,為拜托供給了一種宣布/定閱機制。事宜的定閱與撤消與我們適才講的不雅察者形式中的定閱與撤消相似,只是表示情勢有所分歧。在不雅察者形式中,定閱應用辦法Attach()來停止;在事宜的定閱中應用“+=”。相似地,撤消定閱在不雅察者形式頂用Dettach(),而事宜的撤消用“-=”。
7. 上面例子分離用不雅察者形式,事宜機制來完成
7.1 實例描寫:客戶付出了定單款子,這時候財政須要開具發票,出納須要記賬,配送員須要配貨。
7.2 不雅察者形式的完成
7.2.1 類圖
7.2.2 代碼完成
/// <summary> /// 籠統不雅察者 /// </summary> public interface ISubject { void Notify(); } /// <summary> /// 任務崗亭,作為這裡的不雅察者的籠統 /// </summary> public abstract class JobStation { public abstract void Update(); } /// <summary> /// 詳細主題,這裡是客戶 /// </summary> public class Customer : ISubject { private string customerState; private IList<JobStation> observers = new List<JobStation>(); /// <summary> /// 增長不雅察者 /// </summary> /// <param name="observer"></param> public void Attach(JobStation observer) { this.observers.Add(observer); } /// <summary> /// 移除不雅察者 /// </summary> /// <param name="observer"></param> public void Detach(JobStation observer) { this.observers.Remove(observer); } /// <summary> /// 客戶狀況 /// </summary> public string CustomerState { get { return customerState; } set { customerState = value; } } public void Notify() { foreach (JobStation o in observers) { o.Update(); } } } /// <summary> /// 管帳 /// </summary> public class Accountant : JobStation { private string accountantState; private Customer customer; public Accountant(Customer customer) { this.customer = customer; } /// <summary> /// 更新狀況 /// </summary> public override void Update() { if (customer.CustomerState == "已付款") { Console.WriteLine("我是管帳,我來開具發票。"); accountantState = "已開辟票"; } } } /// <summary> /// 出納 /// </summary> public class Cashier : JobStation { private string cashierState; private Customer customer; public Cashier(Customer customer) { this.customer = customer; } public override void Update() { if (customer.CustomerState == "已付款") { Console.WriteLine("我是出納員,我給掛號入賬。"); cashierState = "已入賬"; } } } /// <summary> /// 配送員 /// </summary> public class Dilliveryman : JobStation { private string dillivierymanState; private Customer customer; public Dilliveryman(Customer customer) { this.customer = customer; } public override void Update() { if (customer.CustomerState == "已付款") { Console.WriteLine("我是配送員,我來發貨。"); dillivierymanState = "已發貨"; } } }
7.2.3 客戶端代碼
class Program { static void Main(string[] args) { Customer subject = new Customer(); subject.Attach(new Accountant(subject)); subject.Attach(new Cashier(subject)); subject.Attach(new Dilliveryman(subject)); subject.CustomerState = "已付款"; subject.Notify(); Console.Read(); } }
運轉成果:
我是管帳,我來開具發票。
我是出納員,我給掛號入賬。
我是配送員,我來發貨。
7.3 事宜完成
7.3.1 類圖
經由過程類圖來看,不雅察者和主題之間曾經不存在任何依附關系了。
7.3.2 代碼完成
/// <summary> /// 籠統主題 /// </summary> public interface ISubject { void Notify(); } /// <summary> /// 聲明拜托 /// </summary> public delegate void CustomerEventHandler(); /// <summary> /// 詳細主題 /// </summary> public class Customer : ISubject { private string customerState; // 聲明一個拜托事宜,類型為 CustomerEventHandler public event CustomerEventHandler Update; public void Notify() { if (Update != null) { // 應用事宜來告訴給定閱者 Update(); } } public string CustomerState { get { return customerState; } set { customerState = value; } } } /// <summary> /// 財政,曾經不須要完成籠統的不雅察者類,而且不消援用詳細的主題 /// </summary> public class Accountant { private string accountantState; public Accountant() { } /// <summary> /// 開辟票 /// </summary> public void GiveInvoice() { Console.WriteLine("我是管帳,我來開具發票。"); accountantState = "已開辟票"; } } /// <summary> /// 出納,曾經不須要完成籠統的不雅察者類,而且不消援用詳細的主題 /// </summary> public class Cashier { private string cashierState; public void Recoded() { Console.WriteLine("我是出納員,我給掛號入賬。"); cashierState = "已入賬"; } } /// <summary> /// 配送員,曾經不須要完成籠統的不雅察者類,而且不消援用詳細的主題 /// </summary> public class Dilliveryman { private string dillivierymanState; public void Dilliver() { Console.WriteLine("我是配送員,我來發貨。"); dillivierymanState = "已發貨"; } }
7.3.3 客戶端代碼
class Program { static void Main(string[] args) { Customer subject = new Customer(); Accountant accountant = new Accountant(); Cashier cashier = new Cashier(); Dilliveryman dilliveryman = new Dilliveryman(); // 注冊事宜 subject.Update += accountant.GiveInvoice; subject.Update += cashier.Recoded; subject.Update += dilliveryman.Dilliver; /* * 以上寫法也能夠用上面代碼來調換 subject.Update += new CustomerEventHandler(accountant.GiveInvoice); subject.Update += new CustomerEventHandler(cashier.Recoded); subject.Update += new CustomerEventHandler(dilliveryman.Dilliver); */ subject.CustomerState = "已付款"; subject.Notify(); Console.Read(); } }
運轉成果
我是管帳,我來開具發票。
我是出納員,我給掛號入賬。
我是配送員,我來發貨。