• <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 长葛 | 连云港 | 莱芜 | 临夏 | 桐城 | 黄冈 | 琼中 | 包头 | 西藏拉萨 | 宜昌 | 永新 | 扬州 | 基隆 | 万宁 | 鞍山 | 乌兰察布 | 东台 | 沧州 | 周口 | 玉林 | 泰州 | 包头 | 泰安 | 铁岭 | 山南 | 绍兴 | 濮阳 | 周口 | 乌兰察布 | 资阳 | 湛江 | 儋州 | 平潭 | 广饶 | 西双版纳 | 海丰 | 东莞 | 赵县 | 海东 | 济源 | 南通 | 如东 | 江苏苏州 | 天门 | 乌兰察布 | 黔西南 | 迪庆 | 五指山 | 呼伦贝尔 | 定州 | 海南海口 | 海北 | 喀什 | 宿迁 | 阿里 | 内蒙古呼和浩特 | 澄迈 | 保亭 | 靖江 | 葫芦岛 | 达州 | 鞍山 | 丹阳 | 桐乡 | 营口 | 大同 | 新泰 | 海丰 | 绍兴 | 海拉尔 | 中卫 | 榆林 | 邹城 | 台北 | 绍兴 | 呼伦贝尔 | 吴忠 | 武安 | 荆州 | 河池 | 淮南 | 宁波 | 清徐 | 玉环 | 海门 | 咸阳 | 泸州 | 新泰 | 儋州 | 娄底 | 株洲 | 青海西宁 | 吉林 | 宁夏银川 | 诸暨 | 神农架 | 酒泉 | 吐鲁番 | 河池 | 高密 | 泰兴 | 锡林郭勒 | 沭阳 | 潍坊 | 咸宁 | 厦门 | 曹县 | 邯郸 | 启东 | 开封 | 青州 | 六安 | 桂林 |