設計模式之門面模式

0x01.定義與類型

  • 定義:又叫門面模式,提供了一個統一的接口,用來訪問子系統中的一羣接口
  • 外觀模式定義了一個高層接口,讓子系統更容易使用
  • 類型:結構型
  • UML類圖

門面模式

  • 門面模式是對系統複雜的關係處理作了一個封裝,對外提供一個簡單的接口,成員介紹:html

    • 子系統:被門面模式封裝的子系統,也是具體業務邏輯的細節
    • facade類:門面類,對子系統執行流程進行封裝,對外開放功能接口,通常爲單例對象。

0x02.適用場景

  • 子系統愈來愈複雜,增長外觀模式提供簡單調用接口
  • 構建多層系統結構,利用外觀對象做爲每層的入口,簡化層間調用

0x03.優勢

  • 簡化了調用過程,無需瞭解深刻子系統,防止帶來風險
  • 減小系統依賴、鬆散耦合
  • 更好的劃分訪問層次
  • 符合迪米特法則,即最少知道原則

0x04.缺點

  • 增長子系統,須要修改門面類,容易引入風險。
  • 修改門面類,不符合開閉原則

0x05.樣例代碼

場景:假設積分兌換物品流程,一共有三部分別依賴三個子系統
1.積分校驗系統,查看是否有資格。
2.積分支付系統,兌換禮物,扣減積分等。
3.物流系統,兌換禮物後,進行配送流程。
  • 若是不適用門面模式,須要在客戶端進行三個步驟的調用,而門面封裝後只須要使用門面類,下面具體代碼實現:
/**
 * 禮物實體類
 */
public class PointsGift {

    private String name;

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

    public String getName() {
        return name;
    }

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

/**
 * 支付子系統
 */
public class PointsPaymentService {
    public boolean pay(PointsGift pointsGift) {
        //扣減積分
        System.out.println("支付:" + pointsGift.getName() + " 積分紅功!");
        return true;
    }
}

/**
 * 積分校驗子系統
 */
public class QualifyService {

    public boolean isAvailable (PointsGift pointsGift) {
        System.out.println("校驗" + pointsGift.getName() + "積分資格經過,庫存經過");
        return true;
    }
}

/**
 * 物流子系統
 */
public class ShippingService {
    public String shipGift (PointsGift pointsGift) {
        //物流系統的對接邏輯
        System.out.println(pointsGift.getName() + "進入物流系統");
        return "666";
    }
}

/**
 * 扣減積分門面類
 */
public class GiftExchangeService {

    /**
     * 模擬注入
     */
    private QualifyService qualifyService = new QualifyService();
    private PointsPaymentService pointsPaymentService = new PointsPaymentService();
    private ShippingService shippingService = new ShippingService();

    //模擬注入,一開始就已經有了三個依賴的子系統
//    public void setQualifyService(QualifyService qualifyService) {
//        this.qualifyService = qualifyService;
//    }
//
//    public void setPointsPaymentService(PointsPaymentService pointsPaymentService) {
//        this.pointsPaymentService = pointsPaymentService;
//    }
//
//    public void setShippingService(ShippingService shippingService) {
//        this.shippingService = shippingService;
//    }

    public void giftExchange (PointsGift pointsGift) {
        if (qualifyService.isAvailable(pointsGift)) {
            //資格校驗經過
            if (pointsPaymentService.pay(pointsGift)) {
                //若是支付積分紅功
                String shippingOrderNo = shippingService.shipGift(pointsGift);
                System.out.println("物流訂單號:" + shippingOrderNo);
            }
        }
    }
}
  • 測試與調用類
/**
 * 客戶端與測試類
 */
public class Test {

    public static void main(String[] args) {
        PointsGift pointsGift = new PointsGift("連衣裙");
        GiftExchangeService giftExchangeService = new GiftExchangeService();

//        giftExchangeService.setQualifyService(new QualifyService());
//        giftExchangeService.setPointsPaymentService(new PointsPaymentService());
//        giftExchangeService.setShippingService(new ShippingService());

        giftExchangeService.giftExchange(pointsGift);
    }
}
  • 測試輸出結果:
校驗連衣裙積分資格經過,庫存經過
支付:連衣裙 積分紅功!
連衣裙進入物流系統
物流訂單號:666
  • 樣例UML

門面模式樣例

0x06.相關的設計模式

  • 外觀模式和中介者模式java

    • 外觀模式關注的是外界和子系統直接的交互
    • 中介者模式關注的是子系統之間的交互
  • 外觀模式和單例模式git

    • 外觀模式中外觀對象能夠作成單例對象來使用
  • 外觀模式和抽象工廠模式github

    • 外觀類能夠經過抽象工廠獲取子系統實例
    • 子系統能夠在內部對外觀類進行屏蔽

0x07.源碼中的外觀模式

  • SpringJDBC中的:JdbcUtils是對JDBC的封裝
  • MyBatis: Configuration中new開頭的方法
  • Tomcat: RequestFacade類
  • Tomcat: Request類
  • Tomcat: ResponseFacade類
  • Tomcat: StandardSessionFacade類

0x08.代碼地址

門面模式: https://github.com/sigmako/design-pattern/tree/master/facade設計模式

0x09.參考

相關文章
相關標籤/搜索