1. 程式人生 > >觀察者模式2種用法---結合代理模式實現

觀察者模式2種用法---結合代理模式實現

在安卓的內容提供者ContentProvider,RxJava都運用到了觀察者模式
今天來了解並學習下觀察者模式,希望在自己編寫程式碼時候,更多的運用此模式

什麼是觀察者模式呢?
我是這樣理解觀察者模式的,當我去使用一個設計模式時候,我很喜歡將抽象的問題具體化
1、被觀察者
2、被觀察者的行為
3、觀察者
4、觀察者的行為
5、關聯2者的類(簡單的可以在被觀察者裡面去關聯2者)

首先先來了解一個最簡單的觀察者模式,我就拿一個最經典的例子來解釋
我和小明(觀察者)去訂報(觀察者行為),郵局(被觀察者)有報紙(被觀察者行為)就會通知我和小明

那麼首先來看觀察者的方法吧,觀察者裡面只有一個介面,就是郵件給我報紙,我就有報紙了,只有這一個方法

ObserverInterface

package com.godinsec;
//訂閱者
public interface ObserverInterface {
    // 有新的報紙了就會被執行通知
    void HasNewPaper();
}

再看來下觀察者類的具體實現吧,也就是我和小明,對外提供了一個setP_name和 getP_name的方法
ObserverImpl

package com.godinsec;
public class ObserverImpl implements ObserverInterface {
    // 訂閱者的名字
    private
String p_name; public ObserverImpl(String f_name) { p_name = f_name; } public String getP_name() { return p_name; } public void setP_name(String p_name) { this.p_name = p_name; } // 告訴訂閱者有新報紙了 public void HasNewPaper() { System.out.println(p_name + "!! 有新的報紙了,請查收!"
); } }

然後就該涉及到被觀察者方法介面這塊了,也就是郵局實體類的方法,其實郵局最好只有傳送報紙的介面實現,哪些新增取消訂閱者,最好抽取出來一個新的類,我們就先看看被觀察者擁有訂閱取消的功能吧
它裡面只有新增和訂閱,以及自己的方法,那就是傳送報紙的功能
ObserveredInterface

package com.godinsec;
 public interface ObserveredInterface
   {
       //新增訂閱者
       void RegisterSubscriber(ObserverInterface f_subScribe);
       //取消訂閱
       void RemoveSubScriber(ObserverInterface f_subScribe);
       //傳送報紙
       void SendPaper();
   }

繼續看下被觀察者,也就是我和小明的實體類
ObserveredImpl

package com.godinsec;
import java.util.ArrayList;
import java.util.List;
//人民日報
public class ObserveredImpl implements ObserveredInterface {
    private List<ObserverInterface> subList = new ArrayList<ObserverInterface>();
    public void RegisterSubscriber(ObserverInterface f_subScribe) {
        subList.add(f_subScribe);
    }
    public void RemoveSubScriber(ObserverInterface f_subScribe) {
        if (subList.indexOf(f_subScribe) >= 0) {
            subList.remove(f_subScribe);
        }
    }
    @Override
    public void SendPaper() {
        for (int i = 0; i < subList.size(); i++) {
            ObserverImpl observerImpl = (ObserverImpl) subList.get(i);
            System.out.println("----發報紙----"+observerImpl.getP_name());
            subList.get(i).HasNewPaper();
        }
    }
}

通過新增訂閱的方式,然後在呼叫自己的方法SendPaper,去為每一個訂閱者傳送郵報,呵呵,這跟代理模式灰常像呀,如果你想了解代理模式,請戳如下連結:

最後看下測試類是如何實現的吧:
MyMainDemo

package com.godinsec;

public class MyMainDemo {
    public static void main(String[] args) {

        ObserveredImpl _paper = new ObserveredImpl();
        ObserverImpl _me = new ObserverImpl("我");
        ObserverImpl _XiaoMing = new ObserverImpl("小明");
        // 小明訂報
        _paper.RegisterSubscriber(_XiaoMing);
        // 趙雲訂報
        // 劉備訂報
        _paper.RegisterSubscriber(_me);
        // 有新報紙了
        _paper.SendPaper();

        System.out.println("---------------發完報紙了------------------");
        // 小明不想訂了,取消報紙
        _paper.RemoveSubScriber(_XiaoMing);
        // 又有新報紙了 就沒有小明的報紙 了
        _paper.SendPaper();

    }
}

看下日誌輸出:

----發報紙----小明
小明!! 有新的報紙了,請查收!
----發報紙----
我!! 有新的報紙了,請查收!
---------------發完報紙了------------------
----發報紙----
我!! 有新的報紙了,請查收!


我們來改進改進上面那個觀察者模式
以上就是一個灰常簡單的觀察者模式,那麼我們接下來進行改造,郵局只有傳送郵報的方法,讓訂閱取消訂閱方法抽取出來

觀察者及其觀察者的方法沒有做更改還是如下的程式碼:
ObserverInterface

package com.godinsec;
//訂閱者
public interface ObserverInterface {
    // 有新的報紙了就會被執行通知
    void HasNewPaper();
}

ObserverImpl

package com.godinsec;
public class ObserverImpl implements ObserverInterface {
    // 訂閱者的名字
    private String p_name;
    public ObserverImpl(String f_name) {
        p_name = f_name;
    }

    public String getP_name() {
        return p_name;
    }
    public void setP_name(String p_name) {
        this.p_name = p_name;
    }
    // 告訴訂閱者有新報紙了
    public void HasNewPaper() {
        System.out.println(p_name + "!! 有新的報紙了,請查收!");
    }
}

接下來看被觀察者類,及其介面方法,這個做了更改,只有傳送郵報的功能,取消了,訂閱和取消訂閱的功能,程式碼如下:
ObserveredInterface

package com.godinsec;
import java.util.List;
public interface ObserveredInterface {
    // 傳送報紙
    void SendPaper(List<ObserverInterface> subList);
}

ObserveredImpl

package com.godinsec;
import java.util.ArrayList;
import java.util.List;
//人民日報
public class ObserveredImpl implements ObserveredInterface {
    @Override
    public void SendPaper(List<ObserverInterface> subList) {
        for (int i = 0; i < subList.size(); i++) {
            ObserverImpl observerImpl = (ObserverImpl) subList.get(i);
            System.out.println("----發報紙----"+observerImpl.getP_name());
            subList.get(i).HasNewPaper();
        }
    }
}

最後我們新添加了一個控制類,就是將訂閱,取消訂閱摘出來了
ControllerInterface

package com.godinsec;
import java.util.List;
public interface ControllerInterface {
       //新增訂閱者
    void RegisterSubscriber(ObserverInterface f_subScribe);
    //取消訂閱
    void RemoveSubScriber(ObserverInterface f_subScribe);

    //傳送報紙
    void SendPaper();
}

ControllerImpl

package com.godinsec;
import java.util.ArrayList;
import java.util.List;
public class ControllerImpl implements ControllerInterface{
    private List<ObserverInterface> subList = new ArrayList<ObserverInterface>();
    ObserveredImpl observeredImpl;
    @Override
    public void RegisterSubscriber(ObserverInterface f_subScribe) {
        subList.add(f_subScribe);
    }
    @Override
    public void RemoveSubScriber(ObserverInterface f_subScribe) {
        if (subList.indexOf(f_subScribe) >= 0) {
            subList.remove(f_subScribe);
        }
    }
    public ControllerImpl(ObserveredImpl observeredImpl) {
        super();
        this.observeredImpl = observeredImpl;   
    }
    @Override
    public void SendPaper() {
        observeredImpl.SendPaper(subList);
    }
}

最後來看下主介面程式碼把
MyMainDemo

package com.godinsec;

public class MyMainDemo {
    public static void main(String[] args) {

        ObserverImpl _me = new ObserverImpl("我");
        ObserverImpl _XiaoMing = new ObserverImpl("小明");

        ObserveredImpl _paper = new ObserveredImpl();

        ControllerInterface controllerImpl = new ControllerImpl(_paper);

        controllerImpl.RegisterSubscriber(_me);
        controllerImpl.RegisterSubscriber(_XiaoMing);

        // 有新報紙了
        controllerImpl.SendPaper();

        System.out.println("---------------發完報紙了------------------");
        // 小明不想訂了,取消報紙
        controllerImpl.RemoveSubScriber(_XiaoMing);
        // 又有新報紙了 就沒有小明的報紙 了
        controllerImpl.SendPaper();

    }
}

log輸出如下:

----發報紙----
我!! 有新的報紙了,請查收!
----發報紙----小明
小明!! 有新的報紙了,請查收!
---------------發完報紙了------------------
----發報紙----
我!! 有新的報紙了,請查收!