All About JAVA 關於設計模式中的“觀察者模式”

來源:互聯網
上載者:User

        觀察者模式描述了一種一對多的關係,其中“一”被稱作“主題對象/資訊發行者”,“多”被稱所“觀察者”。用觀察者和主題對象的這種稱謂來解釋觀察者模式:存在多個觀察者類需要“取得”和“使用”一個主題類中提供的全部或者部分特定的資料,並且當特定的資料發生變動時,觀察者會自動得到更新的資料並執行一系列操作。拿網路中經常提到的“訂閱”這種行為可以很形象的比喻觀察者模式,比如一個人很喜歡團購,他希望每當有新的團購資訊的時候能收到通知,於是他可以在團購網站通過註冊並留下電郵地址的方式來訂閱團購資訊,這時團購網站便會將這個人的電郵地址儲存到系統中的通知清單中,通知清單中儲存了很多同樣希望得到最新團購資訊的使用者的電郵地址,當團購網有新的團購資訊時,便會將新的團購資訊發往列表中的每一個電郵地址,也就是每個訂閱了資訊的使用者都會收到一封內容相同的電子郵件,當某些使用者希望不再收到類似郵件時還可以在郵件中點擊類似“不再收到此類郵件”的連結進行退訂,也就是團購網站會將此人的電郵資訊從通知清單中刪除。在“訂閱”這一系列行為中,使用者充當了觀察者的角色,團購網站服務提供者充當了主題對象的角色。

        上邊說到觀察者類需要“取得”和“使用”主題類提供的去全部或者部分特定的資料,這裡“取得”應該怎麼進行?一般來說“取得”可以分為兩種方式:一、觀察者得到資料變動的通知後自己到主題中讀取自己需要的資料這種方式稱之為pull;二、當主題資料變動時將所有資料全部發送給觀察者而不管觀察者是否都用的到,這種方式稱之為push。

        知道了觀察者模式的原理以及取得資料的兩種方式,接下來可以看看針對使用者與團購網之間的“訂閱”這種行為的代碼實現:

        針對這個實現我們需要一個 主題對象interface、一個觀察者interface、一個實現了主題對象interface的團購網對象類、兩個實現了觀察者interface的使用者類還有一個測試類別。

        主題對象interface代碼:

package com.rong.l.observer;</p><p>/**<br /> * Created on Dec 13, 2010<br /> * @version 1.0<br /> * @update 修改日期 修改描述<br /> */<br />public interface Subjecter<br />{<br /> // registerObserver與<br /> // removeObserver方法的參數是實現了<br /> // Observer介面類型的對象<br /> // 將使用者(觀察者)註冊到最新團購語音總機列表中<br /> public void registerObserver(Observer o);<br /> // 將使用者(觀察者)從通知清單中刪除<br /> public void removeObserver(Observer o);<br /> // 在有新的團購資訊時使用此方法通知所有觀察者<br /> public void notifyObservers();<br />}<br /> 

        實現了主題對象interface的團購網對象類:

package com.rong.l.observer;</p><p>import java.util.ArrayList;</p><p>/**<br /> * Created on Dec 13, 2010<br /> * @version 1.0<br /> * @update 修改日期 修改描述<br /> */<br />public class GroupPurchseInfo implements Subjecter<br />{<br /> private ArrayList<Observer> observers; // 用來存放加入到通知隊列的觀察者</p><p> private String title; // 團購標題</p><p> private String description; // 團購描述</p><p> private int leastNumberToStart; // 團購最低人數</p><p> public GroupPurchseInfo() // 建構函式<br /> {<br /> // 建立一個預設的存放觀察者的空列表<br /> observers = new ArrayList<Observer>();<br /> }</p><p> /**<br /> * <p>Description:[將觀察者註冊到主題對象的通知清單中]</p><br /> * @param o<br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */</p><p> public void registerObserver(Observer o)<br /> {<br /> observers.add(o);<br /> }</p><p> /**<br /> * <p>Description:[將觀察者從主題對象的通知清單中刪除]</p><br /> * @param o<br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */</p><p> public void removeObserver(Observer o)<br /> {<br /> int i = observers.indexOf(o);<br /> if (i >= 0)<br /> {<br /> observers.remove(i);<br /> }<br /> }</p><p> /**<br /> * <p>Description:[通知所有主題對象通知清單中的觀察者]</p><br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */</p><p> public void notifyObservers()<br /> {<br /> // 迴圈觀察者列表,分別執行每個觀察者的update方法<br /> for (int i = 0; i < observers.size(); i++)<br /> {<br /> Observer observer = (Observer) observers.get(i);<br /> // 所有的觀察者都實現了Observer介面的update方法,所以這裡可以<br /> // 不管observer對象到底是什麼類型,只要知道它可以執行update方法就可以了。<br /> observer.update(title, leastNumberToStart, description);<br /> }<br /> }</p><p> /**<br /> *<br /> * <p>Discription:[更新一條團購資訊]</p><br /> * @param title<br /> * @param leastNumberToStart<br /> * @param description<br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */<br /> public void addNewGroupPurchseInfo(String title, int leastNumberToStart,<br /> String description)<br /> {<br /> this.title = title;<br /> this.leastNumberToStart = leastNumberToStart;<br /> this.description = description;<br /> hasNewInfo();<br /> }</p><p> /**<br /> * <p>Discription:[當團購內容出現更新時調用此方法,通知所有觀察者(執行觀察者的update方法)]</p><br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */</p><p> private void hasNewInfo()<br /> {<br /> notifyObservers();</p><p> }<br />}<br />

        觀察者interface代碼:

package com.rong.l.observer;</p><p>/**<br /> * Created on Dec 13, 2010<br /> * @version 1.0<br /> * @update 修改日期 修改描述<br /> */<br />public interface Observer<br />{<br /> // update方法<br /> public void update(String title, int leastNumberToStart, String description);<br />}<br />   

        使用者類1:

package com.rong.l.observer;</p><p>/**<br /> * Created on Dec 13, 2010<br /> * @version 1.0<br /> * @update 修改日期 修改描述<br /> */<br />public class Customer implements Observer<br />{<br /> // 存放當前觀察者註冊到的主題,以後可以用這個引用執行remove等操作。<br /> private Subjecter currentSubject;</p><p> // 團購資訊標題<br /> private String title;</p><p> // 團購資訊描述<br /> private String description;</p><p> // 團購最少人數<br /> private int leastNumberToStart;</p><p> /**<br /> * <p>Discription:[構造器方法描述]</p><br /> * @coustructor 方法.<br /> */<br /> public Customer(Subjecter currentSubject)<br /> {<br /> // 建立這個觀察者對象時,根據傳入的主題對象,<br /> // 自動將建立的觀察者對象註冊到主題對象的通知清單中。<br /> this.currentSubject = currentSubject;<br /> currentSubject.registerObserver(this);<br /> }</p><p> /**<br /> * <p>Discription:[將當前觀察者從主題對象通知清單中刪除]</p><br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */<br /> public void unRegisterMe()<br /> {<br /> // 這裡的currentSubject為此觀察者註冊到的主題對象的引用<br /> currentSubject.removeObserver(this);<br /> }</p><p> /**<br /> * <p>Discription:[實現Observer介面的方法,用與當主題對象資料發生改變時針對當前類型觀察者所做的一系列操作]</p><br /> * @param title<br /> * @param leastNumberToStart<br /> * @param description<br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */</p><p> public void update(String title, int leastNumberToStart, String description)<br /> {<br /> this.title = title;<br /> this.description = description;<br /> this.leastNumberToStart = leastNumberToStart;<br /> contentOfEmail();<br /> }</p><p> /**<br /> * <p>Discription:[輸出目前使用者收到的團購資訊]</p><br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */</p><p> public void contentOfEmail()<br /> {<br /> System.out.println("CustomerOne收到資訊:今日團購:" + title + ",團購最少人數:"<br /> + String.valueOf(leastNumberToStart) + ",團購描述:" + description);<br /> }</p><p>}<br />

        使用者類2:

package com.rong.l.observer;</p><p>/**<br /> * Created on Dec 13, 2010<br /> * @version 1.0<br /> * @update 修改日期 修改描述<br /> */<br />public class AnotherCustomer implements Observer<br />{</p><p> private Subjecter currentSubject;</p><p> private String title;</p><p> private String description;</p><p> private int leastNumberToStart;</p><p> /**<br /> * <p>Discription:[構造器方法描述]</p><br /> * @coustructor 方法.<br /> */<br /> public AnotherCustomer(Subjecter currentSubject)<br /> {<br /> this.currentSubject = currentSubject;<br /> currentSubject.registerObserver(this);<br /> }</p><p> /**<br /> * <p>Discription:[方法功能中文描述]</p><br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */<br /> public void unRegisterMe()<br /> {<br /> currentSubject.removeObserver(this);<br /> }</p><p> /**<br /> * <p>Discription:[方法功能中文描述]</p><br /> * @param title<br /> * @param leastNumberToStart<br /> * @param description<br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */</p><p> public void update(String title, int leastNumberToStart, String description)<br /> {<br /> this.title = title;<br /> this.description = description;<br /> this.leastNumberToStart = leastNumberToStart;<br /> contentOfEmail();<br /> }</p><p> /**<br /> * <p>Discription:[方法功能中文描述]</p><br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */</p><p> public void contentOfEmail()<br /> {<br /> System.out.println("CustomerTwo收到資訊:今日團購:" + title + ",團購最少人數:"<br /> + String.valueOf(leastNumberToStart) + ",團購描述:" + description);<br /> }</p><p>}<br />

        測試類別:

 package com.rong.l.observer;</p><p>/**<br /> * Created on Dec 14, 2010<br /> * @version 1.0<br /> * @update 修改日期 修改描述<br /> */<br />public class TestMain<br />{</p><p> /**<br /> * <p>Description:[方法功能中文描述]</p><br /> * @param args<br /> * @author:榮磊<br /> * @update:[日期YYYY-MM-DD] [更改人姓名][變更描述]<br /> */</p><p> public static void main(String[] args)<br /> {<br /> GroupPurchseInfo groupPurchseInfo = new GroupPurchseInfo();// 建立主題對象<br /> Customer customerOne = new Customer(groupPurchseInfo); // 建立一個觀察者<br /> // 建立另外一個觀察者<br /> AnotherCustomer customerAnotherOne = new AnotherCustomer(groupPurchseInfo); </p><p> // 更新主題對象的團購資訊,輸出第一行,第二行<br /> groupPurchseInfo.addNewGroupPurchseInfo("團購KTV", 8, "4小時優惠,包括自助餐!");<br /> // 將觀察者1從主題對象的通知清單中去除<br /> customerOne.unRegisterMe();<br /> // 更新主題對象的團購資訊,輸出第三行<br /> groupPurchseInfo.addNewGroupPurchseInfo("團購KTV2", 8, "4小時優惠,包括自助餐!");<br /> // 將觀察者2從主題對象的通知清單中去除<br /> customerAnotherOne.unRegisterMe();<br /> // 更新主題對象的團購資訊,這次兩個觀察者全部從主題對象的通知清單中去除,所以無輸出<br /> groupPurchseInfo.addNewGroupPurchseInfo("團購KTV3", 8, "4小時優惠,包括自助餐!");<br /> }<br />}<br />

 

輸出:

CustomerOne收到資訊:今日團購:團購KTV,團購最少人數:8,團購描述:4小時優惠,包括自助餐!
CustomerTwo收到資訊:今日團購:團購KTV,團購最少人數:8,團購描述:4小時優惠,包括自助餐!
CustomerTwo收到資訊:今日團購:團購KTV2,團購最少人數:8,團購描述:4小時優惠,包括自助餐!

  

以上代碼描述的實際上是使用push的方式使觀察者得到資料,觀察者的update方法有固定的3個參數,是每個觀察者都得到的。

那pull方式應該是怎麼樣的?pull方式其實就是在主題對象調用notifyObservers()方法時每當執行相應觀察者update()方法時將主題對象自身的引用作為參數傳入,這樣在觀察者的update(Subjecter s)方法中就可以使用s.get**();的方發來取得觀察者實際需要的資料了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.