1. 程式人生 > >設計模式之觀察者模式(例項+Demo)

設計模式之觀察者模式(例項+Demo)

你能從本文了解到如下幾個方面:1. 什麼是觀察者模式?2. 如何使用觀察者模式。 3. Java中的觀察者模式的使用。 4. 總結。5. 原始碼

1. 什麼是觀察者模式?

觀察者模式又被稱為釋出訂閱模式。它定義了物件之間一對多的依賴,當一個物件狀態發生改變時,它的所有依賴者都會收到通知並自動更新相關內容。我們可以拿報社來舉例:一家報社(Subject)一發布報紙,就會立馬派送給所有訂報(Obsever)的人,訂報的人就能獲取報紙內容。當然我們的觀察者模式比報社的及時性更高。

2. 如何使用觀察者模式?

就上面的問題,我們現在來做這樣一個需求:將報社釋出的新報紙派送到所有訂閱者的手裡。

思路:
1. 首先我們建立一個主題類介面:ISubject,所有被觀察者都可以繼承這個介面(這裡指報社)
2. 我們建立一個報社類(NewsPaperOffice),實現主題類介面(ISubject)
3. 我們給所有的訂閱者建立一個收到訊息的介面(IObserver)
4. 所有的訂閱者實現這個介面。

這裡寫圖片描述

程式碼實現:

public interface ISubject {//主題介面
    void registerObserver(IObserver iObserver);
    void removeObserver(IObserver iObserver);
    void
notifyObserver(); }
public class NewsPaperOffice implements ISubject {//報社(主題)
    private int time = 1;
    private List<IObserver> mList = new ArrayList<>();

    @Override
    public void registerObserver(IObserver iObserver) {
        if (iObserver != null) {
            mList.add(iObserver);
        }
    }

    @Override
public void removeObserver(IObserver iObserver) { mList.remove(iObserver); } @Override public void notifyObserver() { for (int i = 0; i < mList.size(); i++) { mList.get(i).update("第"+time +"次發的新聞"); } time ++ ; } }
public interface IObserver {//觀察者介面
    void update(String s);
}
public class FirstObserver implements IObserver {//觀察者實現
    private String message;

    public String getMessage() {
        return message;
    }

    @Override
    public void update(String s) {
        message = "FirstObserver 收到了" + s;
    }
}
public class SecondObserver implements IObserver {//觀察者實現
    private String message;

    public String getMessage() {
        return message;
    }

    @Override
    public void update(String s) {
        message = "SecondObserver 收到了" + s;
    }
}

實現一個簡單的邏輯呼叫:

public class ObserverActivity extends AppCompatActivity {

    @BindView(R.id.btn_send_broadcast)
    Button mBtnSendBroadcast;
    @BindView(R.id.first_observer_tv)
    TextView mFirstObserverTv;
    @BindView(R.id.first_observer_btn)
    Button mFirstObserverBtn;
    @BindView(R.id.second_observer_tv)
    TextView mSecondObserverTv;
    @BindView(R.id.sencond_observer_btn)
    Button mSencondObserverBtn;

    private NewsPaperOffice mNewsPaperOffice;
    private FirstObserver mFirstObserver;
    private SecondObserver mSecondObserver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_obaser);
        ButterKnife.bind(this);
    }

    @OnClick({R.id.btn_send_broadcast, R.id.first_observer_btn, R.id.sencond_observer_btn})
    public void onViewClicked(View view) {
        if (mNewsPaperOffice == null) {
            mNewsPaperOffice = new NewsPaperOffice();
        }
        switch (view.getId()) {
            case R.id.btn_send_broadcast:
                mNewsPaperOffice.notifyObserver();
                if (mFirstObserver != null) {
                    mFirstObserverTv.setText(mFirstObserver.getMessage());
                }
                if (mSecondObserver != null) {
                    mSecondObserverTv.setText(mSecondObserver.getMessage());
                }
                break;
            case R.id.first_observer_btn:
                if (mFirstObserver == null) {
                    mFirstObserver = new FirstObserver();
                }
                if(mFirstObserverBtn.getText().equals("訂閱報紙")){
                    mFirstObserverBtn.setText("取消訂閱");
                    mNewsPaperOffice.registerObserver(mFirstObserver);
                }else{
                    mFirstObserverBtn.setText("訂閱報紙");
                    mNewsPaperOffice.removeObserver(mFirstObserver);
                }
                break;
            case R.id.sencond_observer_btn:
                if (mSecondObserver == null) {
                    mSecondObserver = new SecondObserver();
                }
                if(mSencondObserverBtn.getText().equals("訂閱報紙")){
                    mSencondObserverBtn.setText("取消訂閱");
                    mNewsPaperOffice.registerObserver(mSecondObserver);
                }else{
                    mSencondObserverBtn.setText("訂閱報紙");
                    mNewsPaperOffice.removeObserver(mSecondObserver);
                }
                break;
        }
    }
}

這裡寫圖片描述
至此我們已經實現了一個觀察者模式。

3.JAVA中的觀察者模式的使用

Java中的觀察者模式主題需要繼承java.util.Observable,觀察者需要實現java.util.Observer。通過notifyObservers()方法傳送通知,在呼叫此方法之前需要呼叫setChanged()修改傳送狀態。

主題類(NewsPaperOfficeJava):

public class NewsPaperOfficeJava extends Observable {
    private String message;
    private int time = 1;

    public void sendMessage(){
        message = "第"+time +"次發的新聞";
        setChanged();
        notifyObservers();
        time++;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

觀察者的實現:

public class FirstObserverJava implements Observer {//JAVA觀察者實現
    private String message;
    Observable mObservable;

    public String getMessage() {
        return message;
    }

    @Override
    public void update(Observable o, Object arg) {
        mObservable = o;
        if(mObservable instanceof NewsPaperOfficeJava){
            message = "FirstObserver 收到了" + ((NewsPaperOfficeJava) mObservable).getMessage();
        }
    }
}

……

實現邏輯和第一種實現方式差不多,修改下型別和方法即可,不做贅述。

4. 總結

使用Java的觀察者模式的弊端: 前面有提到過,Java中的觀察者主題需要繼承java.util.Observable,這樣就會導致一個問題,如果說我們上面的NewsPaperOfficeJava需要具有另外一個超類的行為時,這時候就會比較麻煩,因為Java中咱們不能使用多繼承去實現。當然,如果我們自己能夠去擴充套件java.util.Observable,那麼還是可以去使用的,一般情況下推薦自己實現一套觀察者模式。

5. 原始碼