初學 Java 設計模式(十七):實戰中介者模式 「菜鳥驛站」

1、中介者模式介紹

1. 解決的問題

主要解決當對象與對象之間存在大量關聯關係時,若一個對象發生改變,要跟蹤與之相關的對象,同時作出相應處理的問題。java

2. 定義

中介者模式是一種行爲設計模式,能減小對象之間混亂無序的依賴關係。該模式會限制對象之間的直接交互,迫使它們經過一箇中介者對象進行合做。git

3. 應用場景

  • 當一些對象與其餘對象緊密耦合以致於難以對其進行修改時,可以使用中介者模式。
  • 當組件因過於依賴其餘組件而沒法在不一樣應用中複用時,可以使用中介者模式。
  • 爲了在不一樣情景下複用一些基本行爲,致使須要被迫建立大量組件子類時,可以使用終結者模式。

2、中介者模式優缺點

1. 優勢

  • 單一職責原則:能夠將多個組件間的交流抽取到同一位置,使其更易於理解和維護。
  • 開閉原則:無需修改實際組件就能增長新的中介者。
  • 能夠減輕應用中多個組件的耦合狀況。
  • 能夠更方便地複用各個組件。

2. 缺點

  • 一段時間後,中介者可能會演化爲上帝對象。

3、中介者模式應用實例:菜鳥驛站

1. 實例場景

相信你們平時快遞來不及拿的話,大部分時候都會選擇讓快遞小哥將快遞放到菜鳥驛站,咱們在放學/下班後再去菜鳥驛站拿本身的快遞。同時,咱們若是有快遞須要寄出,也是如今菜鳥驛站填寫寄件單,而後快遞小哥從菜鳥驛站拿到快遞,發貨。github

其實在這裏,菜鳥驛站就是一箇中介者,承擔着快遞小哥和咱們之間的重要交流樞紐。express

今天,咱們就以菜鳥驛站爲例,介紹一下中介者模式。設計模式

2. 中介者模式實現

2.1 工程結構
mediator-pattern
└─ src
    ├─ main
    │    └─ java
    │    └─ org.design.pattern.mediator
    │       ├─ model
    │       │    ├─ ExpressPackage.java
    │       │    ├─ Courier.java
    │       │    └─ User.java
    │       └─ service
    │            ├─ CourierStation.java
    │            └─ impl
    │                 └─ CaiNiaoCourierStation.java
    └─ test
        └─ java
            └─ org.design.pattern.mediator
                  └─ CourierStationTest.java
2.2 代碼實現
2.2.1 實體類

快遞包裹併發

/**
 * 快遞包裹
 */
@Getter
@Setter
@AllArgsConstructor
public class ExpressPackage {

    /**
     * 包裹id
     */
    private String id;

    /**
     * 包裹名稱
     */
    private String name;

    /**
     * 收件人電話
     */
    private String consigneePhoneNumber;

    /**
     * 發件快遞站
     */
    private CourierStation sendCourierStation;

    /**
     * 收件快遞站
     */
    private CourierStation receiveCourierStation;
}

快遞員ide

/**
 * 快遞員
 */
@Slf4j
@Getter
@Setter
@AllArgsConstructor
public class Courier {

    /**
     * 快遞員id
     */
    private String id;

    /**
     * 快遞員姓名
     */
    private String name;

    /***
     * 送快遞(放到快遞站)
     *
     * @param expressPackage 快遞包裹
     */
    public void sendExpressPackage(ExpressPackage expressPackage) {
        expressPackage.getReceiveCourierStation().receiveExpressPackage(expressPackage);
    }

    /**
     * 收快遞(從快遞站取件,併發貨)
     *
     * @param expressPackage 快遞包裹
     */
    public void receiveExpressPackage(ExpressPackage expressPackage) {
        log.info(
            "The courier {} has arrived in the hands of the express package {}, and it will be sent to you immediately.",
            this.getName(),
            expressPackage.getName()
        );
    }
}

用戶測試

/**
 * 用戶
 */
@Getter
@Setter
@AllArgsConstructor
public class User {

    /**
     * 用戶id
     */
    private String id;

    /**
     * 用戶姓名
     */
    private String name;

    /**
     * 用戶電話
     */
    private String phone;

    /**
     * 寄快遞(快遞放到快遞站)
     *
     * @param expressPackage 快遞包裹
     */
    public void sendExpressPackage(ExpressPackage expressPackage) {
        expressPackage.getSendCourierStation().sendExpressPackage(expressPackage);
    }
}
2.2.2 服務類

快遞站中介者優化

/**
 * 快遞站
 */
public interface CourierStation {

    /**
     * 收件服務
     *
     * @param expressPackage 快遞包裹
     */
    void receiveExpressPackage(ExpressPackage expressPackage);

    /**
     * 寄件服務
     *
     * @param expressPackage 快遞包裹
     */
    void sendExpressPackage(ExpressPackage expressPackage);
}

菜鳥驛站this

/**
 * 菜鳥驛站
 */
@Slf4j
@Getter
@Setter
public class CaiNiaoCourierStation implements org.design.pattern.mediator.service.CourierStation {

    /**
     * 快遞員列表
     */
    private List<Courier> courierList;

    /**
     * 收件服務
     *
     * @param expressPackage 快遞包裹
     */
    @Override
    public void receiveExpressPackage(ExpressPackage expressPackage) {
        log.info(
            "The package {} has arrived at the cai niao courier station, please pick it up as soon as possible.",
            expressPackage.getName()
        );
    }

    /**
     * 寄件服務
     *
     * @param expressPackage 快遞包裹
     */
    @Override
    public void sendExpressPackage(ExpressPackage expressPackage) {
      Optional<Courier> courierOptional = courierList.stream().findAny();
      if (courierOptional.isPresent()) {
          Courier courier = courierOptional.get();
          courier.receiveExpressPackage(expressPackage);
      }
    }
}
2.3 測試驗證
2.3.1 測試驗證類
/**
 * 快遞站測試類
 */
public class CourierStationTest {

    @Test
    public void testReceiveExpressPackage() {
        Courier courier = new Courier("1", "快遞小哥");
        CaiNiaoCourierStation courierStation = new CaiNiaoCourierStation();
        courierStation.setCourierList(Collections.singletonList(courier));
        ExpressPackage expressPackage = new ExpressPackage(
                "1", "PS5", "13245678910", null, courierStation
        );
        courier.sendExpressPackage(expressPackage);
    }

    @Test
    public void testSendExpressPackage() {
        User user = new User("1", "張三", "13245678910");
        Courier courier = new Courier("1", "快遞小哥");
        CaiNiaoCourierStation courierStation = new CaiNiaoCourierStation();
        courierStation.setCourierList(Collections.singletonList(courier));
        ExpressPackage expressPackage = new ExpressPackage(
                "1", "Kindle", "13245678910", courierStation, null
        );
        user.sendExpressPackage(expressPackage);
    }
}
2.3.2 測試結果
22:19:52.811 [main] INFO  o.d.p.m.s.impl.CaiNiaoCourierStation - The package PS5 has arrived at the cai niao courier station, please pick it up as soon as possible.
22:19:52.814 [main] INFO  o.d.pattern.mediator.model.Courier - The courier 快遞小哥 has arrived in the hands of the express package Kindle, and it will be sent to you immediately.

Process finished with exit code 0

4、中介者模式結構

中介者模式-模式結構圖

  1. 組件(Component)是包含各類業務邏輯的類。每一個組件都有一個指向中介者的引用,該引用被聲明爲中介者接口類型。組件不知道中介者實際所屬的類,所以可經過鏈接到不一樣的中介者使其能在其餘程序中複用。
  2. 中介者(Mediator)接口聲明瞭與組件交流的方法,但一般僅包含一個通知方法。組件可將任意上下文(包括自身對象)做爲該方法的參數,只有這樣接收組件和發送者類纔不會耦合。
  3. 具體中介者(Concrete Mediator)封裝了多種組件間的關係。具體中介者一般會保存全部組件的引用並對其進行管理,甚至有時會對其生命週期進行管理。
  4. 組件並不知道其餘組件的狀況。若是組件內發生了重要事件,它只能通知中介者。中介者收到通知後能輕易肯定發送者,這就足以判斷下一步要觸發的組件。

    對於組件來講,中介者看上去徹底就是一個黑箱。發送者不知道最終會由誰來處理自身的請求,接收者也不知道請求究竟來自於誰。

設計模式並不難學,其自己就是多年經驗提煉出的開發指導思想,關鍵在於多加練習,帶着使用設計模式的思想去優化代碼,就能構建出更合理的代碼。

源碼地址:https://github.com/yiyufxst/design-pattern-java

參考資料:
小博哥重學設計模式:https://github.com/fuzhengwei/itstack-demo-design
深刻設計模式:https://refactoringguru.cn/design-patterns/catalog

相關文章
相關標籤/搜索