觀察者模式

觀察者模式定義了對(duì)象之間的1:N的依賴關(guān)系,當(dāng)一個(gè)被觀察對(duì)象的狀態(tài)改變時(shí)馋记,其N個(gè)觀察依賴對(duì)象都會(huì)得到通知和更新,這種設(shè)計(jì)模式在系統(tǒng)設(shè)計(jì)中也被稱為發(fā)布-訂閱模式鸽粉,廣泛應(yīng)用于系統(tǒng)解偶設(shè)計(jì)。

觀察者設(shè)計(jì)模式中,多個(gè)觀察者對(duì)象正在觀察特定的主題對(duì)象拨齐,當(dāng)主題對(duì)象內(nèi)部狀態(tài)發(fā)生變化時(shí),觀察者注冊(cè)到主題對(duì)象中獲得通知昨寞。

觀察者對(duì)象可以自由的從訂閱主題中注入與注銷瞻惋,達(dá)到系統(tǒng)松耦合的設(shè)計(jì)目的。

什么時(shí)候使用觀察者模式

在我們進(jìn)行系統(tǒng)設(shè)計(jì)的時(shí)候援岩,如果存在多個(gè)對(duì)象狀態(tài)變化依賴某一個(gè)特定主題對(duì)象內(nèi)部狀態(tài)變化的時(shí)候歼狼,則可以應(yīng)用觀察者模式。

image

首先需要明確我們的主題對(duì)象享怀,其次我們將觀察者注入并觀察其內(nèi)部狀態(tài)變更羽峰,我們可以采用主動(dòng)觀察其狀態(tài)變更行為或者被動(dòng)接受行為變更時(shí)的通知,觀察者當(dāng)觀察到變更時(shí)執(zhí)行各自的行為添瓷。

觀察者模式案例

在電子商務(wù)領(lǐng)域主要圍繞線上商品交易打造限寞,其中核心的模塊是訂單的生命周期,這個(gè)是觀察者模式應(yīng)用的典型場(chǎng)景仰坦,因?yàn)槲覀兊南到y(tǒng)服務(wù)需要在訂單的各個(gè)狀態(tài)變更時(shí)作出即時(shí)的內(nèi)部操作或者用戶服務(wù)等履植;如果我們應(yīng)用觀察者模式來訂閱訂單狀態(tài)變更事件那么會(huì)為系統(tǒng)降低模塊之間的代碼耦合度。

image

觀察者模式設(shè)計(jì)

image
  • Order:觀察者觀察對(duì)象悄晃,案例圍繞Order的內(nèi)部狀態(tài)變更來設(shè)計(jì)的發(fā)布訂閱
  • OrderUpdateManager:Order狀態(tài)維護(hù)對(duì)象玫霎,扮演即時(shí)通知的角色
  • Observer:觀察者接口抽象,將其實(shí)現(xiàn)類對(duì)象注冊(cè)與注銷綁定至OrderUpdateManager
  • DeliveredObserver:觀察者實(shí)現(xiàn)妈橄,觀察Order狀態(tài)變更庶近,作出相應(yīng)的應(yīng)對(duì)事件

Order.java

package com.iblog.pattern.observe;

public class Order {
    public String id;
    public Status status;

    public enum Status {
        RECEIVED,
        AWAIT_PAYMENT,
        PAYMENT_RECEIVED,
        PROCESSING,
        EXCEPTION,
        SHIPPED,
        DELIVERED
    }
}

Observer.java

package com.iblog.pattern.observe;

public interface Observer {
    void observe(Event event);
}

PaymentNotifyObserver.java

package com.iblog.pattern.observe;

public class PaymentNotifyObserver implements Observer {
    @Override
    public void observe(Event event) {
        if (event.preStatus != Order.Status.RECEIVED) {
            return;
        }
        System.out.println("notify the order owner to pay for order");
    }
}

PaidFinalsObserver.java

package com.iblog.pattern.observe;

public class PaidFinalsObserver implements Observer {
    @Override
    public void observe(Event event) {
        if (event.preStatus != Order.Status.AWAIT_PAYMENT) {
            return;
        }
        System.out.println("user paid for order, notify finals to check bill");
    }
}

ReceivedPaymentObserver.java

package com.iblog.pattern.observe;

public class ReceivedPaymentObserver implements Observer {
    @Override
    public void observe(Event event) {
        if (event.preStatus != Order.Status.PAYMENT_RECEIVED) {
            return;
        }
        System.out.println("received the payment of order, notify to process the order");
    }
}

DeliveredObserver.java

package com.iblog.pattern.observe;

public class DeliveredObserver implements Observer {
    @Override
    public void observe(Event event) {
        if (event.preStatus != Order.Status.SHIPPED) {
            return;
        }
        System.out.println("order is delivered, notify use to check the package");
    }
}

OrderUpdateManager.java

package com.iblog.pattern.observe;

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

public class OrderUpdateManager {
    private final List<Observer> observers = new ArrayList<>();
    private final Notifier notifier;

    public OrderUpdateManager() {
        this.notifier = new Notifier(observers);
    }

    public void register(Observer observer) {
        synchronized (observers) {
            observers.add(observer);
        }
    }

    public void unregister(Observer observer) {
        synchronized (observers) {
            observers.remove(observer);
        }
    }

    public void awaitPaidOrder(Order order) {
        notifier.notify(order, Order.Status.AWAIT_PAYMENT, "paid order");
    }

    public void receivedOrder(Order order) {
        notifier.notify(order, Order.Status.RECEIVED, "await payment");
    }

    public void paidOrder(Order order) {
        notifier.notify(order, Order.Status.PAYMENT_RECEIVED, "will process order");
    }

    public void delivered(Order order) {
        notifier.notify(order, Order.Status.SHIPPED, "delivered");
    }
}

Event.java

package com.iblog.pattern.observe;

public class Event {
    public final Order order;
    public final Order.Status preStatus;
    public final String message;

    public Event(Order order, Order.Status preStatus, String message) {
        this.order = order;
        this.preStatus = preStatus;
        this.message = message;
    }
}

Notifier.java

package com.iblog.pattern.observe;

import java.util.List;

public class Notifier {
    private final List<Observer> observers;

    public Notifier(List<Observer> observers) {
        this.observers = observers;
    }

    public void notify(Order order, Order.Status preStatus, String subject) {
        for (Observer o : observers) {
            o.observe(new Event(order, preStatus, subject));
        }
    }
}

MockTest.java

package com.iblog.pattern.observe;

public class MockTest {
    public static void main(String[] args) {
        Order order = new Order();
        order.id = "1";
        order.status = Order.Status.RECEIVED;

        OrderUpdateManager manager = new OrderUpdateManager();
        Observer observer1 = new PaymentNotifyObserver();
        Observer observer2 = new PaidFinalsObserver();
        Observer observer3 = new ReceivedPaymentObserver();
        Observer observer4 = new DeliveredObserver();
        manager.register(observer1);
        manager.register(observer2);
        manager.register(observer3);
        manager.register(observer4);

        order.status = Order.Status.AWAIT_PAYMENT;
        manager.receivedOrder(order);
        order.status = Order.Status.PAYMENT_RECEIVED;
        manager.awaitPaidOrder(order);
        order.status = Order.Status.PROCESSING;
        manager.paidOrder(order);
        order.status = Order.Status.DELIVERED;
        manager.delivered(order);
    }
}

輸出:

notify the order owner to pay for order
user paid for order, notify finals to check bill
received the payment of order, notify to process the order
order is delivered, notify use to check the package

Jdk中觀察者模式

Observer Java Doc
Observable Java Doc

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市眷蚓,隨后出現(xiàn)的幾起案子鼻种,更是在濱河造成了極大的恐慌,老刑警劉巖沙热,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叉钥,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡篙贸,警方通過查閱死者的電腦和手機(jī)投队,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來爵川,“玉大人敷鸦,你說我怎么就攤上這事。” “怎么了扒披?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵值依,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我碟案,道長(zhǎng)鳞滨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任蟆淀,我火速辦了婚禮拯啦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘熔任。我一直安慰自己褒链,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布疑苔。 她就那樣靜靜地躺著甫匹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪惦费。 梳的紋絲不亂的頭發(fā)上兵迅,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音薪贫,去河邊找鬼恍箭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛瞧省,可吹牛的內(nèi)容都是我干的扯夭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼鞍匾,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼交洗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起橡淑,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤构拳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后梁棠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體置森,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年掰茶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了暇藏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡濒蒋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沪伙,我是刑警寧澤瓮顽,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站围橡,受9級(jí)特大地震影響暖混,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜翁授,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一拣播、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧收擦,春花似錦贮配、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宴猾,卻和暖如春圆存,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仇哆。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工沦辙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人讹剔。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓怕轿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親辟拷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撞羽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容