門面模式(Facade Pattern)

在以前信息不是很發達的時代,人們最快捷的信息往來方式就是通過書信,一般我們寫一封書信,一般要經過一下幾個步驟:

  1. 在信紙上寫上新的內容
  2. 在信封上寫上收件人的姓名,地址信息
  3. 將信裝進信封,貼上郵票
  4. 把信送給郵局投遞

用類圖表示就如下所示:
這裏寫圖片描述

首先定義一個接口,規範寫信的方法:

package facade;
/**
 * 寫信接口
 * @author 77473
 *
 */
public interface ILetterProcess {

    public void writeContext(String context);//寫信的內容

    public void writeEnvelope(String address);//寫信封地址

    public void putLetterIntoEnvelope();//將信放入信封

    public void sendLetter();//寄信

}

然後定義一個類實現ILetterProcess的方法

package facade;
/**
 * 寫信實現類
 * @author 77473
 *
 */
public class LetterProcessImpl implements ILetterProcess{

    public void writeContext(String context) {
        // TODO Auto-generated method stub
        System.out.println("填寫信的內容:"+context);
    }

    public void writeEnvelope(String address) {
        // TODO Auto-generated method stub
        System.out.println("填寫收件人地址及姓名:"+address);
    }

    public void putLetterIntoEnvelope() {
        // TODO Auto-generated method stub
        System.out.println("將信放入信封中...");
    }

    public void sendLetter() {
        // TODO Auto-generated method stub
        System.out.println("郵寄信件....");
    }

}

最後在場景類中模擬一個寫信操作

package facade;
/**
 * 場景類
 * @author 77473
 *
 */
public class Client {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ILetterProcess letterProcess=new LetterProcessImpl();
        letterProcess.writeContext("Hello,It's me,do you know who I am? I'm your old lover. I'd like to..");
        letterProcess.writeEnvelope("Happy Road No. 666,God Province,Heaven");
        letterProcess.putLetterIntoEnvelope();
        letterProcess.sendLetter();
    }

}

測試結果:
這裏寫圖片描述

結果完全正確,但是我們回過頭來看看這個過程, 它與高內聚的要求相差甚遠, 更不要說迪米特法則、 接口隔離原則了。 你想想, 你要知道這4個步驟, 而且還要知道它們的順序, 一旦出錯, 信就不可能郵寄出去, 這在面向對象的編程中是極度地不適合, 它根本就沒有完成一個類所具有的單一職責。還有, 如果信件多了就非常麻煩, 每封信都要這樣運轉一遍, 非得累死。還好, 現在郵局開發了一個新業務, 你只要把信件的必要信息告訴我, 我給你發, 我來完成這4個過程, 只要把信件交給我就成了, 其他就不要管了。 非常好的方案! 我們來看類圖:

這裏寫圖片描述

其他類不變增加了一個ModernPostOffice類封裝寫信的整個流程,並且暴露一個sendLetter()方法給外部調用:

package facade;
/**
 * 現代郵局類
 * @author 77473
 *
 */
public class ModernPostOffice {

    private ILetterProcess letterProcess=new LetterProcessImpl();//寫信流程對象

    //寫信,封裝,投遞一體化
    public void sendLetter(String context,String address){
        //寫信的內容
        letterProcess.writeContext("Hello,It's me,do you know who I am? I'm your old lover. I'd like to..");
        //寫信封地址
        letterProcess.writeEnvelope("Happy Road No. 666,God Province,Heaven");
        //將信放入信封
        letterProcess.putLetterIntoEnvelope();
        //郵遞信件
        letterProcess.sendLetter();
    }
}

用戶不需要知道寫信具體要經過哪些步驟,每個步驟的先後順序,你只要告訴郵局信的內容和收件人地址,郵局就會幫我們把新寄出去了:

package facade;
/**
 * 場景類
 * @author 77473
 *
 */
public class Client {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ModernPostOffice office=new ModernPostOffice();
        office.sendLetter("Hello,It's me,do you know who I am? I'm your old lover. I'd like to..", "Happy Road No. 666,God Province,Heaven");
    }

}

這種方式不僅簡單,而且擴展性非常好,例如非常時期,我們要對信的內容進行一個檢查,此時我們就很容易實現,只需要增加一個Police類:

package facade;
/**
 * 檢查類,檢查新的內容是否健康
 * @author 77473
 *
 */
public class Police {

    //檢查信的內容是否反國家,反人類
    public void checkLetter(ILetterProcess letter){
        System.out.println("已檢查通過,信的內容沒有反國家,反人類傾向...");
    }
}

修改ModernPostOffice.class

package facade;
/**
 * 現代郵局類
 * @author 77473
 *
 */
public class ModernPostOffice {

    private ILetterProcess letterProcess=new LetterProcessImpl();
    private Police police=new Police();//警察叔叔

    //寫信,封裝,投遞一體化
    public void sendLetter(String context,String address){
        //寫信的內容
        letterProcess.writeContext("Hello,It's me,do you know who I am? I'm your old lover. I'd like to..");
        //寫信封地址
        letterProcess.writeEnvelope("Happy Road No. 666,God Province,Heaven");
        police.checkLetter(letterProcess);//警察叔叔檢查信的內容時候健康
        //將信放入信封
        letterProcess.putLetterIntoEnvelope();
        //郵遞信件
        letterProcess.sendLetter();
    }
}

添加一個警察對象,在裝信進信封前,添加警察檢查的流程。場景類不需要修改,運行如下:

這裏寫圖片描述

高層模塊沒有任何改動,但是信已經被檢查過了。這正是我們設計所需要的模式,
不改變子系統對外暴露的接口、 方法, 只改變內部的處理邏輯, 其他兄弟模塊的調用產生了不同的結果, 確實是一個非常棒的設計。 這就是門面模式。

一、定義

Provide a unified interface to a set of interfaces in a subsystem.Facade defines a higher-levelinterface that makes the subsystem easier to use.( 要求一個子系統的外部與其內部的通信必須通過一個統一的對象進行。 門面模式提供一個高層次的接口, 使得子系統更易於使用。 )

示意圖:

這裏寫圖片描述

二、角色

  • Facade門面角色
    客戶端可以調用這個角色的方法。 此角色知曉子系統的所有功能和責任。 一般情況下,本角色會將所有從客戶端發來的請求委派到相應的子系統去, 也就說該角色沒有實際的業務邏輯, 只是一個委託類。
  • subsystem子系統角色
    可以同時有一個或者多個子系統。 每一個子系統都不是一個單獨的類, 而是一個類的集合。 子系統並不知道門面的存在。 對於子系統而言, 門面僅僅是另外一個客戶端而已。

三、優點

  1. 減少系統的相互依賴
    想想看, 如果我們不使用門面模式, 外界訪問直接深入到子系統內部, 相互之間是一種
    強耦合關係, 你死我就死, 你活我才能活, 這樣的強依賴是系統設計所不能接受的, 門面模
    式的出現就很好地解決了該問題, 所有的依賴都是對門面對象的依賴, 與子系統無關。
  2. 提高了靈活性
    依賴減少了, 靈活性自然提高了。 不管子系統內部如何變化, 只要不影響到門面對象,任你自由活動。
  3. 提高安全性
    想讓你訪問子系統的哪些業務就開通哪些邏輯, 不在門面上開通的方法, 你休想訪問到。

項目地址

發佈了59 篇原創文章 · 獲贊 13 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章