1. 程式人生 > 實用技巧 >閱讀《Design pattern》-觀察者模式

閱讀《Design pattern》-觀察者模式

摘抄《設計模式》

意圖: 定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新 別名: 依賴(dependent),釋出-訂閱(publish-subscribe) 適用性: 在以下情況下可以使用觀察者模式: 一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這二者封裝在獨立的物件中,以使它們可以各自獨立地改變和複用。 對一個物件的改變需要同時改變其他物件,而不知道具體由多少物件需要改變。 一個物件必須通知其他物件,而他又不能假定其他物件是誰。換言之,你不希望這些物件緊密耦合的。
簡單一句話:目標狀態變化,觸發所有觀察者變化。 注意:一對多的關係,一個目標,多個觀察者 目標提供一個方法:用於附上觀察者,便於notify(通知) 觀察者在初始時,關注(訂閱)目標,並附上在目標上。釋放時,取消關注(訂閱),移除。
建立一個簡單的觀察者程式碼:
 1 /**
 2  * 觀察者模式-目標介面
 3  */
 4 public interface ISubject {
 5     /**
 6      * 附上觀察者
 7      * @param observer 觀察者
 8      */
 9     public void attach(IObserver observer);
10 
11     /**
12      * 移除觀察者
13      * @param observer 觀察者
14      */
15     public void detach(IObserver observer);
16 17 /** 18 * 通知所有觀察者 19 */ 20 public void notifyAllObserver(); 21 }
 1 /**
 2  * 觀察者模式-觀察者介面
 3  */
 4 public interface IObserver {
 5     /**
 6      * 訂閱目標
 7      * @param subject 目標
 8      */
 9     public void subscribe(ISubject subject);
10 
11     /**
12      * 取消訂閱
13      */
14
public void unsubscribe(); 15 16 /** 17 * 業務更新 18 * @param subject 目標 19 */ 20 public void update(ISubject subject); 21 }

上述是介面。下面定義父類基類

 1 /**
 2  * 目標基類/父類
 3  */
 4 public class BaseSubject implements ISubject {
 5     /**
 6      * 觀察者列表
 7      */
 8     protected List<IObserver> observerList;
 9 
10     /**
11      * 建構函式
12      */
13     public BaseSubject() {
14         observerList = new ArrayList<>();
15     }
16 
17     @Override
18     public void attach(IObserver observer) {
19         if (observer != null) {
20             observerList.add(observer);
21         }
22     }
23 
24     @Override
25     public void detach(IObserver observer) {
26         if (observer != null) {
27             observerList.remove(observer);
28         }
29     }
30 
31     @Override
32     public void notifyAllObserver() {
33         for (IObserver item :
34                 observerList) {
35             item.update(this);
36         }
37     }
38 
39     @Override
40     protected void finalize() throws Throwable {
41         for (IObserver item :
42                 observerList) {
43             item.unsubscribe();
44         }
45         observerList.clear();
46         super.finalize();
47     }
48 }
 1 /**
 2  * 觀察者基類/父類
 3  */
 4 public class BaseObserver implements IObserver {
 5     /**
 6      * 目標物件
 7      */
 8     protected ISubject subject;
 9 
10     /**
11      * 建構函式
12      */
13     public BaseObserver() {
14         this.subject = null;
15     }
16 
17     /**
18      * 建構函式
19      * @param subject 目標
20      */
21     public BaseObserver(ISubject subject) {
22         this.subject = null;
23         subscribe(subject);
24     }
25 
26     @Override
27     public void subscribe(ISubject subject) {
28         if (subject != null) {
29             this.subject = subject;
30         }
31         if (this.subject != null) {
32             this.subject.attach(this);
33         }
34     }
35 
36     @Override
37     public void unsubscribe() {
38         if (this.subject != null) {
39             this.subject.detach(this);
40         }
41     }
42 
43     @Override
44     public void update(ISubject subject) {
45         if (subject == this.subject) {
46             // 自己的業務
47         }
48     }
49 
50     @Override
51     protected void finalize() throws Throwable {
52         unsubscribe();
53         this.subject = null;
54         super.finalize();
55     }
56 }

上述是基類/父類,後續再繼承各自的父類,進行實際業務的開展。

【實際業務的程式碼以及測試,這裡不寫了】


特別說明: 在不考慮效率的情況下,上述程式碼可以了。 但更多的時候,更多業務和資源,不允許不限制使用。 說簡單點,在上述的情況下,需要做一個資源優化(比如,重複重新整理、頻繁重新整理、佔用資源過多如何處理、推或拉的效率問題)。這個取決於業務本身。 再比如: 1、需要觀察多個目標,是觀察者模式1對多關係的升級擴充套件 2、更新協議-推拉模型的選定或混用 3、封裝複雜的更新語義