• <menu id="gyiem"><menu id="gyiem"></menu></menu>
  • <menu id="gyiem"><code id="gyiem"></code></menu>

    Java設計模式(四) 觀察者模式

    原創文章,轉載請務必將下面這段話置于文章開頭處(保留超鏈接)。
    本文轉發自技術世界原文鏈接 http://www.luozeyang.com/design_pattern/observer/

    觀察者模式介紹

    觀察者模式定義

    觀察者模式又叫發布-訂閱模式,它定義了一種一對多的依賴關系,多個觀察者對象可同時監聽某一主題對象,當該主題對象狀態發生變化時,相應的所有觀察者對象都可收到通知。

    觀察者模式類圖

    觀察者模式類圖如下(點擊可查看大圖)
    Observer pattern class diagram

    觀察者模式角色劃分

    • 主題,抽象類或接口,如上面類圖中的AbstractSubject
    • 具體主題,如上面類圖中的Subject1,Subject2
    • 觀察者,如上面類圖中的IObserver
    • 具體觀察者,如上面類圖中的Observer1,Observer2,Observer3

    觀察者模式實例

    實例介紹

    獵頭或者HR往往會有很多職位信息,求職者可以在獵頭或者HR那里注冊,當獵頭或者HR有新的崗位信息時,即會通知這些注冊過的求職者。這是一個典型的觀察者模式使用場景。

    實例類圖

    觀察者模式實例類圖如下(點擊可查看大圖)
    Observer pattern example class diagram

    實例解析

    本例代碼可從作者Github下載

    觀察者接口(或抽象觀察者,如本例中的ITalent)需要定義回調接口,如下

    1
    2
    3
    4
    5
    6
    7
    package com.jasongj.observer;

    public interface ITalent {

    void newJob(String job);

    }

    具體觀察者(如本例中的JuniorEngineer,SeniorEngineer,Architect)在回調接口中實現其對事件的響應方法,如

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    package com.jasongj.observer;

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;

    public class Architect implements ITalent {

    private static final Logger LOG = LoggerFactory.getLogger(Architect.class);

    @Override
    public void newJob(String job) {
    LOG.info("Architect get new position {}", job);
    }

    }

    抽象主題類(如本例中的AbstractHR)定義通知觀察者接口,并實現增加觀察者和刪除觀察者方法(這兩個方法可被子類共用,所以放在抽象類中實現),如

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    package com.jasongj.subject;

    import java.util.ArrayList;
    import java.util.Collection;

    import com.jasongj.observer.ITalent;

    public abstract class AbstractHR {

    protected Collection<ITalent> allTalents = new ArrayList<ITalent>();

    public abstract void publishJob(String job);

    public void addTalent(ITalent talent) {
    allTalents.add(talent);
    }

    public void removeTalent(ITalent talent) {
    allTalents.remove(talent);
    }

    }

    具體主題類(如本例中的HeadHunter)只需實現通知觀察者接口,在該方法中通知所有注冊的具體觀察者。代碼如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package com.jasongj.subject;

    public class HeadHunter extends AbstractHR {

    @Override
    public void publishJob(String job) {
    allTalents.forEach(talent -> talent.newJob(job));
    }

    }

    當主題類有更新(如本例中獵頭有新的招聘崗位)時,調用其通知接口即可將其狀態(崗位)通知給所有觀察者(求職者)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    package com.jasongj.client;

    import com.jasongj.observer.Architect;
    import com.jasongj.observer.ITalent;
    import com.jasongj.observer.JuniorEngineer;
    import com.jasongj.observer.SeniorEngineer;
    import com.jasongj.subject.HeadHunter;
    import com.jasongj.subject.AbstractHR;

    public class Client1 {

    public static void main(String[] args) {
    ITalent juniorEngineer = new JuniorEngineer();
    ITalent seniorEngineer = new SeniorEngineer();
    ITalent architect = new Architect();

    AbstractHR subject = new HeadHunter();
    subject.addTalent(juniorEngineer);
    subject.addTalent(seniorEngineer);
    subject.addTalent(architect);

    subject.publishJob("Top 500 big data position");
    }

    }

    觀察者模式優缺點

    觀察者模式優點

    • 抽象主題只依賴于抽象觀察者
    • 觀察者模式支持廣播通信
    • 觀察者模式使信息產生層和響應層分離

    觀察者模式缺點

    • 如一個主題被大量觀察者注冊,則通知所有觀察者會花費較高代價
    • 如果某些觀察者的響應方法被阻塞,整個通知過程即被阻塞,其它觀察者不能及時被通知

    觀察者模式與OOP原則

    已遵循的原則

    • 依賴倒置原則(主題類依賴于抽象觀察者而非具體觀察者)
    • 迪米特法則
    • 里氏替換原則
    • 接口隔離原則
    • 單一職責原則
    • 開閉原則

    未遵循的原則

    • NA

    Java設計模式系列

    郭俊 Jason wechat
    歡迎關注作者微信公眾號【大數據架構】
    您的贊賞將支持作者繼續原創分享
    速赢彩app 许昌 | 安阳 | 荆州 | 昌吉 | 莆田 | 阿克苏 | 雅安 | 赤峰 | 灵宝 | 包头 | 庄河 | 吕梁 | 吉林 | 齐齐哈尔 | 江门 | 十堰 | 浙江杭州 | 云浮 | 内江 | 宝鸡 | 阳江 | 随州 | 长垣 | 潮州 | 黄山 | 湖州 | 芜湖 | 枣庄 | 阿勒泰 | 安康 | 盘锦 | 鄢陵 | 漳州 | 项城 | 青州 | 佛山 | 丹阳 | 大同 | 灌南 | 四川成都 | 鹰潭 | 呼伦贝尔 | 伊春 | 北海 | 七台河 | 项城 | 汉中 | 涿州 | 灌云 | 泗阳 | 杞县 | 河池 | 扬州 | 三河 | 德清 | 新泰 | 长兴 | 鹤岗 | 兴化 | 舟山 | 淄博 | 青海西宁 | 莒县 | 项城 | 垦利 | 巴中 | 垦利 | 嘉兴 | 茂名 | 仙桃 | 张家口 | 内蒙古呼和浩特 | 株洲 | 金坛 | 天长 | 丹阳 | 珠海 | 金昌 | 邵阳 | 大连 | 姜堰 | 咸宁 | 深圳 | 曹县 | 文昌 | 滁州 | 怀化 | 陕西西安 | 景德镇 | 桐城 | 哈密 | 招远 | 宁夏银川 | 厦门 | 乳山 | 江西南昌 | 亳州 | 新余 | 芜湖 | 新泰 | 长垣 | 长葛 | 潜江 | 廊坊 | 聊城 | 德清 | 柳州 | 河源 | 温州 | 三沙 | 阿坝 | 贵州贵阳 | 庄河 |