天天看點

淺學設計模式之觀察者<Observer>模式及在android中的應用

轉自http://www.eoeandroid.com/home.php?mod=space&uid=871316&do=blog&id=48239

最近在學習下設計模式,而加深學習的不錯的方法就是把心得寫出來吧。記錄下自己的了解。現在自己看的書是《head.frist設計模式》這本書。比較不錯,想學習設計模式的朋友可以看下這本書。

        觀察者<observer>模式(有時又被稱為釋出-訂閱<publish/subscribe>模式、模型-視圖<model/view>模式、源-收聽者<source/listener>模式或從屬者<dependents>模式)是軟體設計模式的一種。在此種模式中,一個目标物件管理所有相依于它的觀察者物件,并且在它本身的狀态改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實作。此種模式通常被用來實作事件處理系統。(源自百度百科)

           (五月三十一号修正内容)

        看下結構圖:

淺學設計模式之觀察者<Observer>模式及在android中的應用

     開始一個小例子

observer接口:

[java]

view plaincopy

public interface isubscribe {  

    void getnewpaper();  

}  

實作observer接口的觀察者:

個人訂閱者:

public class personalsubscriber implements isubscribe {  

    private string strname;  

    public void setnewspapername(string strname){  

        this.strname = strname;  

    }  

    public string getnewspapername(){  

        return strname;  

    @override  

    public void getnewpaper() {  

        // todo auto-generated method stub  

        system.out.println("我是個人使用者,我得到了我的報紙:"+getnewspapername());  

企業訂閱者:

public class enterprisesubscriber implements isubscribe {  

        system.out.println("我是企業使用者,我得到了我的報紙:"+getnewspapername());  

被觀察者:subject

public abstract class publish {   

    public list<isubscribe> list;  

    public publish(){  

        list = new arraylist();  

    public void registered(isubscribe isubscribe){  

        list.add(isubscribe);  

    public void unregistered(isubscribe isubscribe){  

        list.remove(isubscribe);  

    public abstract void sendnewspaper();  

這裡使用的是抽象類

下面是實作:

public class postoffice extends publish{  

    public void sendnewspaper() {  

        iterator iterator = list.iterator();  

        while(iterator.hasnext()){  

            ((isubscribe) iterator.next()).getnewpaper();  

        }  

測試:

public static void main(string[] args) {  

        postoffice postoffice = new postoffice();  

        //得到個人使用者  

        personalsubscriber person = new personalsubscriber();  

        person.setnewspapername("《南方周末》");  

        //得到企業使用者  

        enterprisesubscriber enterprise = new enterprisesubscriber();  

        enterprise.setnewspapername("《企業報》");  

        //注冊觀察者  

        postoffice.registered(person);  

        postoffice.registered(enterprise);  

        //發放報紙  

        postoffice.sendnewspaper();  

測試結果:

我是個人使用者,我得到了我的報紙:《南方周末》  

我是企業使用者,我得到了我的報紙:《企業報》  

下面是有些錯誤五月18号版本:後面有錯誤解析!

        舉個例子,張三從郵局訂閱了《南方周末》,李四從郵局訂閱了《新京報》,王五從郵局裡面訂閱了《南方都市報》。當報紙抵達郵局的時候,郵局就會把報紙送遞訂閱者。而不需要訂閱者天天到郵局詢問報紙是否到達郵局。

       下面開始代碼:首先應該是個訂閱者接口:

package cn.demo;  

    //從郵局訂閱報紙  

    public void registered(postoffice postoffice);  

    //從郵局退訂報紙  

    public void unregistered(postoffice postoffice);  

    //擷取報紙名稱  

    public void getnewspaper();  

第三個方法非必須,前兩個方法必須要有。(應修改為前兩個非必須,第三個方法必須有)

然後有三個訂閱者類:

張三:

public class zhangsan implements isubscribe{  

    private string mname;  

    private string mnewspapername;  

    public zhangsan(string mname, string mnewspapername) {  

        this.mname = mname;  

        this.mnewspapername = mnewspapername;  

    public string getname() {  

        return mname;  

    public string getnewspapername() {  

        return mnewspapername;  

    public void registered(postoffice postoffice){  

        postoffice.registerednewspaper(this);  

    public void unregistered(postoffice postoffice){  

        postoffice.unregisterednewspaper(this);  

    public void getnewspaper() {  

        system.out.println("我是"+getname()+",我收到我訂閱的"+getnewspapername());  

李四:

public class lisi implements isubscribe{  

    public lisi(string mname, string mnewspapername) {  

王五:

public class wangwu implements isubscribe{  

    public wangwu(string mname, string mnewspapername) {  

三個訂閱者,都有方法訂閱報紙,或者取消訂閱。其實關于訂閱者的資訊,是存儲在郵局類裡面。

郵局類:(郵局類應該繼承一個抽象類或者接口(subject),這裡沒有實作)

import java.util.arraylist;  

import java.util.list;  

public class postoffice {  

    private list<isubscribe> subscribelist = new arraylist<isubscribe>();  

    public void registerednewspaper(isubscribe subscribe) {  

        subscribelist.add(subscribe);  

    public void unregisterednewspaper(isubscribe subscribe) {  

        if (subscribe != null) {  

            subscribelist.remove(subscribe);  

    public void getnewspaper(boolean bool) {  

        if (bool) {  

            sendnewspaper();  

        for(isubscribe subscribe : subscribelist) {  

            subscribe.getnewspaper();  

在這個類裡面,有變化通知是使用的sendnewspaper()這個方法,周遊所有的訂閱者。

測試類:

        postoffice mpostoffice = new postoffice();  

        isubscribe zhangsan = new zhangsan("張三", "《南方周末》");  

        isubscribe lisi = new lisi("李四", "《新京報》");  

        isubscribe wangwu = new wangwu("王五", "《南方都市報》");  

        //開始訂閱報紙  

        zhangsan.registered(mpostoffice);  

        lisi.registered(mpostoffice);  

        wangwu.registered(mpostoffice);  

        //郵局收到報紙,開始發放  

        mpostoffice.getnewspaper(true);  

        //李四退訂  

        lisi.unregistered(mpostoffice);  

列印結果:

[html]

我是張三,我收到我訂閱的《南方周末》  

我是李四,我收到我訂閱的《新京報》  

我是王五,我收到我訂閱的《南方都市報》  

這裡隻是提供了一個簡單的例子,而且代碼你會發現有備援,三個訂閱者類,幾乎是一樣,因為沒有在類裡面添加他們獨自的屬性,可以用一個person類來替代。這裡寫這三個類是為了顯示清晰。

        關于五月18号的例子,觀察者沒必要有注冊和取消注冊的方法。他們的方法的實作也是調用的被觀察者的注冊和取消注冊,不如直接使用被觀察者的方法。

         在android中,button.setonclicklistener()這個方式是比較常見的觀察者模式:當然,衆所周知,onclick是著名的回調方法,在這裡不會研究回調,不用太在意。

看下代碼:

button button1 = (button)findviewbyid(r.id.button1);  

        button button2 = (button)findviewbyid(r.id.button2);  

        button button3 = (button)findviewbyid(r.id.button3);  

        button1.setonclicklistener(this);  

        button2.setonclicklistener(this);  

        button3.setonclicklistener(this);  

    public void onclick(view v) {  

        switch(v.getid()) {  

        case r.id.button1 :  

//          do some thing         

        case r.id.button2 :  

//          do some thing  

        case r.id.button3 :  

先button.setonclicklistener()進行注冊。相當于郵局中的lisi.registered(mpostoffice),此處錯誤,應該是第一例中的postoffice.registered(person)。onclick響應事件相當于郵局中的

public void sendnewspaper() {  

這個中的subscribe.getnewspaper()這個方法。view.onclicklistener相當于郵局。view也就是button是我們的訂閱者,也就相當于張三。我們也可以在getnewspaper中加一些自己的switch判斷。

       最後,如果我們的郵局要實作類似button這樣的回調這麼實作呢?

isubscribe isubscribe;  

        isubscribe.getnewspaper();  

    } 

繼續閱讀