設(shè)計(jì)模式學(xué)習(xí)19(Java實(shí)現(xiàn))——觀察者模式

寫在前面

  • 記錄學(xué)習(xí)設(shè)計(jì)模式的筆記
  • 提高對設(shè)計(jì)模式的靈活運(yùn)用

學(xué)習(xí)地址

https://www.bilibili.com/video/BV1G4411c7N4

https://www.bilibili.com/video/BV1Np4y1z7BU

參考文章

http://c.biancheng.net/view/1317.html

項(xiàng)目源碼
https://gitee.com/zhuang-kang/DesignPattern

21,觀察者模式

21.1 觀察者模式的定義和特點(diǎn)

觀察者(Observer)模式的定義:指多個(gè)對象間存在一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對象都得到通知并被自動(dòng)更新。這種模式有時(shí)又稱作發(fā)布-訂閱模式、模型-視圖模式,它是對象行為型模式。

觀察者模式是一種對象行為型模式,其主要優(yōu)點(diǎn)如下

  1. 降低了目標(biāo)與觀察者之間的耦合關(guān)系,兩者之間是抽象耦合關(guān)系。符合依賴倒置原則。
  2. 目標(biāo)與觀察者之間建立了一套觸發(fā)機(jī)制。

它的主要缺點(diǎn)如下。

  1. 目標(biāo)與觀察者之間的依賴關(guān)系并沒有完全解除,而且有可能出現(xiàn)循環(huán)引用。
  2. 當(dāng)觀察者對象很多時(shí),通知的發(fā)布會(huì)花費(fèi)很多時(shí)間,影響程序的效率。

21.2 觀察者模式的結(jié)構(gòu)與實(shí)現(xiàn)

實(shí)現(xiàn)觀察者模式時(shí)要注意具體目標(biāo)對象和具體觀察者對象之間不能直接調(diào)用,否則將使兩者之間緊密耦合起來,這違反了面向?qū)ο蟮脑O(shè)計(jì)原則

21.2.1 觀察者模式的結(jié)構(gòu)

  1. 抽象主題(Subject)角色:也叫抽象目標(biāo)類,它提供了一個(gè)用于保存觀察者對象的聚集類和增加、刪除觀察者對象的方法,以及通知所有觀察者的抽象方法。
  2. 具體主題(Concrete Subject)角色:也叫具體目標(biāo)類,它實(shí)現(xiàn)抽象目標(biāo)中的通知方法,當(dāng)具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),通知所有注冊過的觀察者對象。
  3. 抽象觀察者(Observer)角色:它是一個(gè)抽象類或接口,它包含了一個(gè)更新自己的抽象方法,當(dāng)接到具體主題的更改通知時(shí)被調(diào)用。
  4. 具體觀察者(Concrete Observer)角色:實(shí)現(xiàn)抽象觀察者中定義的抽象方法,以便在得到目標(biāo)的更改通知時(shí)更新自身的狀態(tài)。

21.2.1 代碼實(shí)現(xiàn)

在使用微信公眾號時(shí),大家都會(huì)有這樣的體驗(yàn),當(dāng)你關(guān)注的公眾號中有新內(nèi)容更新的話,它就會(huì)推送給關(guān)注公眾號的微信用戶端。我們使用觀察者模式來模擬這樣的場景,微信用戶就是觀察者,微信公眾號是被觀察者,有多個(gè)的微信用戶關(guān)注了程序猿這個(gè)公眾號

關(guān)系類圖

Observer

package com.zhuang.observer;

/**
 * @Classname Observer
 * @Description 抽象觀察者
 * @Date 2021/3/28 14:14
 * @Created by dell
 */

public interface Observer {
    //更新的方法
    void update(String messages);
}

WexinUser

package com.zhuang.observer;

/**
 * @Classname WexinUser
 * @Description 具體觀察者類 實(shí)現(xiàn)更新的方法
 * @Date 2021/3/28 14:14
 * @Created by dell
 */

public class WexinUser implements Observer {
    //用戶名
    private String name;

    public WexinUser(String name) {
        this.name = name;
    }

    public WexinUser() {

    }

    @Override
    public void update(String messages) {
        System.out.println(name + "-->" + messages);
    }
}

Subject

package com.zhuang.observer;

/**
 * @Classname Subject
 * @Description 抽象主題類
 * @Date 2021/3/28 14:15
 * @Created by dell
 */

public interface Subject {
    //增加訂閱者
    public void attach(Observer observer);

    //刪除訂閱者
    public void remove(Observer observer);

    //通知訂閱者更新消息
    public void notify(String messages);
}

SubscriptionSubject

package com.zhuang.observer;

import java.util.ArrayList;
import java.util.List;

/**
 * @Classname SubscriptionSubject
 * @Description 具體主題(具體被觀察者)
 * @Date 2021/3/28 14:15
 * @Created by dell
 */

public class SubscriptionSubject implements Subject {
    //存儲訂閱公眾號的微信用戶
    private List<Observer> weixinUserList = new ArrayList<Observer>();

    @Override
    public void attach(Observer observer) {
        weixinUserList.add(observer);
    }

    @Override
    public void remove(Observer observer) {
        weixinUserList.remove(observer);
    }

    @Override
    public void notify(String messages) {
        for (Observer observer : weixinUserList) {
            observer.update(messages);
        }
    }
}

Client

package com.zhuang.observer;

/**
 * @Classname Client
 * @Description 觀察者模式 測試類
 * @Date 2021/3/28 14:16
 * @Created by dell
 */

public class Client {
    public static void main(String[] args) {
        SubscriptionSubject subject = new SubscriptionSubject();

        //創(chuàng)建微信用戶
        WexinUser user1 = new WexinUser("張三");
        WexinUser user2 = new WexinUser("李四");
        WexinUser user3 = new WexinUser("王五");

        //訂閱公眾號
        subject.attach(user1);
        subject.attach(user2);
        subject.attach(user3);

        //通過訂閱用戶
        subject.notify("您關(guān)注的公眾號更新啦~~~");
    }
}

20.3 觀察者模式應(yīng)用場景

  1. 對象間存在一對多關(guān)系,一個(gè)對象的狀態(tài)發(fā)生改變會(huì)影響其他對象。
  2. 當(dāng)一個(gè)抽象模型有兩個(gè)方面,其中一個(gè)方面依賴于另一方面時(shí),可將這二者封裝在獨(dú)立的對象中以使它們可以各自獨(dú)立地改變和復(fù)用。
  3. 實(shí)現(xiàn)類似廣播機(jī)制的功能,不需要知道具體收聽者,只需分發(fā)廣播,系統(tǒng)中感興趣的對象會(huì)自動(dòng)接收該廣播。
  4. 多層級嵌套使用,形成一種鏈?zhǔn)接|發(fā)機(jī)制,使得事件具備跨域(跨越兩種觀察者類型)通知。

20.4 JDK源碼解析

在 Java 中,通過 java.util.Observable 類和 java.util.Observer 接口定義了觀察者模式,只要實(shí)現(xiàn)它們的子類就可以編寫觀察者模式實(shí)例。

1,Observable類

Observable 類是抽象目標(biāo)類(被觀察者),它有一個(gè) Vector 集合成員變量,用于保存所有要通知的觀察者對象,下面來介紹它最重要的 3 個(gè)方法。

  • void addObserver(Observer o) 方法:用于將新的觀察者對象添加到集合中。

  • void notifyObservers(Object arg) 方法:調(diào)用集合中的所有觀察者對象的 update方法,通知它們數(shù)據(jù)發(fā)生改變。通常越晚加入集合的觀察者越先得到通知。

  • void setChange() 方法:用來設(shè)置一個(gè) boolean 類型的內(nèi)部標(biāo)志,注明目標(biāo)對象發(fā)生了變化。當(dāng)它為true時(shí),notifyObservers() 才會(huì)通知觀察者。

2,Observer 接口

Observer 接口是抽象觀察者,它監(jiān)視目標(biāo)對象的變化,當(dāng)目標(biāo)對象發(fā)生變化時(shí),觀察者得到通知,并調(diào)用 update 方法,進(jìn)行相應(yīng)的工作。

【例】警察抓小偷

警察抓小偷也可以使用觀察者模式來實(shí)現(xiàn),警察是觀察者,小偷是被觀察者。代碼如下:

小偷是一個(gè)被觀察者,所以需要繼承Observable類

package com.zhuang.observer.observable_example;

import java.util.Observable;

/**
 * @Classname Thief
 * @Description 小偷類 繼承Observable接口
 * @Date 2021/3/28 14:36
 * @Created by dell
 */

public class Thief extends Observable {
    private String name;

    public Thief(String name) {
        this.name = name;
    }

    public Thief() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void steal() {
        System.out.println("小偷:我偷東西,有沒有人來抓我?。?!");
        super.setChanged();//默認(rèn)為true
        super.notifyObservers();
    }
}

警察是一個(gè)觀察者,所以需要讓其實(shí)現(xiàn)Observer接口

package com.zhuang.observer.observable_example;

import java.util.Observable;
import java.util.Observer;

/**
 * @Classname Policemen
 * @Description 警察類 實(shí)現(xiàn)Observe類  實(shí)現(xiàn)update方法
 * @Date 2021/3/28 14:36
 * @Created by dell
 */

public class Policemen implements Observer {

    private String name;

    public Policemen(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Policemen() {
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("警察:" + ((Thief) o).getName() + "你被我抓到了哈哈哈哈!??!");
    }
}

客戶端代碼

package com.zhuang.observer.observable_example;

/**
 * @Classname Client
 * @Description 測試類
 * @Date 2021/3/28 14:36
 * @Created by dell
 */

public class Client {
    public static void main(String[] args) {
        //小偷對象
        Thief thief = new Thief("法外狂徒張三");
        //警察對象
        Policemen policemen = new Policemen("小莊警察");
        //警察盯著小偷
        thief.addObserver(policemen);
        //小偷行竊
        thief.steal();
    }
}


寫在最后

  • 如果我的文章對你有用,請給我點(diǎn)個(gè)??,感謝你??!
  • 有問題,歡迎在評論區(qū)指出!??
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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