Observer模式

java的設(shè)計模式


作用 當觀察對象的狀態(tài)發(fā)生變化時,通知給觀察者(觀察者訂閱被觀察者的狀態(tài))
應(yīng)用 需要根據(jù)對象狀態(tài)進行相應(yīng)處理的場景

Observer.png

創(chuàng)建Subject類

package com.company;

import javax.swing.text.html.HTMLDocument;
import java.util.ArrayList;
import java.util.Iterator;

public abstract class Subject{

    private ArrayList observers = new ArrayList();//保存Observer們
    public void addObserver(Observer observer){
        observers.add(observer);
    };//注冊O(shè)beserver
    public void notifyObservers(){
        //向Observer發(fā)送通知
        Iterator it = observers.iterator();
        while (it.hasNext()){
            Observer observer = (Observer)it.next();
            observer.update();
        }
    }
    public abstract int getState();
    public abstract void setState();\\寫成抽象方法,便于拓展
}

Subject的子類

package com.company;

import java.util.Random;

public class Subjecta extends Subject{
    private int number;
    private Random random = new Random();

    @Override
    public int getState() {
        return number;
    }

    @Override
    public void setState() {
        for(int i = 0 ;i < 10 ;i++){
            number = random.nextInt(48);
            notifyObservers();
        }
    }
}

創(chuàng)建抽象Observer類

package com.company;

public abstract class Observer {
    protected Subject subject;\\有Subject類的實例化對象,便于獲取被觀察者的信息
    public abstract void update();\\在子類中實現(xiàn)更新的具體操作
}

創(chuàng)建實體觀察類

package com.company;

public class Observera extends Observer{
    public Observera(Subject subject){
        this.subject = subject;
        this.subject.addObserver(this);
    }

    @Override
    public void update() {
        System.out.println( "Observera : " + subject.getState());
    }
}

public class Observerb extends Observer{
    public Observerb(Subject subject){
        this.subject = subject;
        this.subject.addObserver(this);
    }

    @Override
    public void update() {
        System.out.print("Observerb : ");
        for(int i = 0 ;i< subject.getState();i++) {
            System.out.print('-');
        }
        System.out.println();
    }
}

在客戶端(Main)使用

package com.company;

public class Main {

    public static void main(String[] args) {
        Subject subject = new Subjecta();
        new Observera(subject);
        new Observerb(subject);\\創(chuàng)建觀察者

        subject.setState();\\設(shè)置狀態(tài)(改變狀態(tài))
    }
}

另一種實現(xiàn)方法

  • 抽象Observer類變?yōu)闉?code>接口——ObserverI
  • Subject的實例化對象subject變成接口ObserverI的update()方法的參數(shù)(原來是抽象類Observer的私有成員)
package com.company;

public interface ObserverI {
    public abstract void update(Subject subject);
}
  • Observer類由抽象類變成了接口,Subject類中添加觀察者的方法和向Observer發(fā)送通知的方法也應(yīng)當重寫
public abstract class Subject{

    private ArrayList observers = new ArrayList();//保存Observer們
    public void addObserver(Observer observer){
        observers.add(observer);
    };//第一種,注冊obeserver

    public void addObserver(ObserverI observer){
        observers.add(observer);
    };//第二種方法,注冊O(shè)beserver的方式

    public void notifyObservers(){
        //向Observer發(fā)送通知
        Iterator it = observers.iterator();
        while (it.hasNext()){
            Observer observer = (Observer)it.next();
            observer.update();
        }
    }//第一種

    public void notifyObservers2(){
        //向Observer發(fā)送通知
        Iterator it = observers.iterator();
        while (it.hasNext()){
            ObserverI observer = (ObserverI)it.next();
            observer.update(this);//改變后的update方法需要傳入一個subject進去
        }
    }//第二種方法
//注意:在狀態(tài)改變后(setState)應(yīng)當調(diào)用的發(fā)送通知的方法也應(yīng)當換成第二種對應(yīng)的
}

  • 繼承ObserverI接口,實現(xiàn)具體方法
package com.company;

public class ObserverI1 implements ObserverI{
    @Override
    public void update(Subject subject) {
        System.out.println( "Observera : " + subject.getState());
    }
}

public class ObserverI2 implements ObserverI{
    @Override
    public void update(Subject subject) {
        System.out.print("Observerb : ");
        for(int i = 0 ;i< subject.getState();i++) {
            System.out.print('-');
        }
        System.out.println();
    }
}

  • 由于ObserverI接口只有抽象方法,在Observer的具體實現(xiàn)類中沒有Subject類的實例化對象作為類成員,無法在構(gòu)造函數(shù)中直接添加observer(注冊observer),需要在客戶端(Main)添加
//第一種注冊observer的方式
public class Observerb extends Observer{
    public Observerb(Subject subject){
        this.subject = subject;
        this.subject.addObserver(this);//改變后
    }
}//第一種只要創(chuàng)建了Subject具體實現(xiàn)類的實例化對象,就在被觀察者中添加了觀察者,

//第二種方法,注冊O(shè)bserver的方式
public class Main {

    public static void main(String[] args) {
        Subject subject = new Subjecta();
        Observer observer1 = new Observera();
        Observer observer2 = new Observerb();//創(chuàng)建觀察者
            subject.addObserver(observer1);
            subject.addObserver(observer2);
        subject.setState();\\設(shè)置狀態(tài)(改變狀態(tài))
    }
}//現(xiàn)在,創(chuàng)建觀察者后,還需調(diào)用被觀察者中添加觀察者的方法)

注意點

Observer的順序

Subject角色中有多個Observer角色,在示例代碼中是先注冊的Observer的update方法先被調(diào)用

Observer的行為對Subject的影響

Subject的狀態(tài)變化 ---> 通知Observer ---> Observer調(diào)用Subject的方法 ---> 導(dǎo)致Subject的狀態(tài)發(fā)生變化 ---> 通知Observer
導(dǎo)致方法被循環(huán)調(diào)用

update方法傳入的參數(shù)

void update(Subject subject); 
void update(int number);  
void update(Subject subject,int number); 

可以傳入Subject實例對象,也可以傳入該實例中的某些數(shù)據(jù),第一種更加靈活

拓展
java.utill.Observer 接口
java.utill.Observable 類 ——被觀察的Subject角色

 public void update(Observable obj,Object arg)//Object類的實例是附加信息

缺陷Subject角色必須是java.utill.Observable 類的子類,但是java是單一繼承

以上完整的代碼上傳到了github倉庫
https://github.com/chenshuyuhhh/DesignPatternDemo.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考資料:菜鳥教程之設(shè)計模式 設(shè)計模式概述 設(shè)計模式(Design pattern)代表了最佳的實踐,通常被有經(jīng)驗...
    Steven1997閱讀 1,281評論 1 12
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,896評論 18 399
  • 1. 想起讀這本書的源頭是一部網(wǎng)絡(luò)劇---《靈魂擺渡》,當初是沖著趙吏這個角色的扮演者于毅才開始看劇,我想每個人心...
    蘇蘇書書閱讀 345評論 0 3
  • I:重述 WHAT: 這個片段講述的是如何運用減壓三步法得到全面的放松和休息。 WHY: 現(xiàn)在生活工作節(jié)奏不斷加快...
    假裝Yes閱讀 192評論 0 0
  • 親子日記第125篇 中午看到牛老師在家長群里發(fā)的她已經(jīng)執(zhí)教完成,現(xiàn)在已經(jīng)在回家的路上了,我眼睛不知不覺就濕...
    一年級七班王爍樺媽媽閱讀 188評論 0 1

友情鏈接更多精彩內(nèi)容