設計模式第六講-外觀模式

小宇渣渣渣發表於2019-01-15

簡介

外觀模式(Facade,門面模式), 為子系統中額外一組介面提供一個一致的介面,此模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。

在專案開發和實際運用中十分頻繁,但是其極易理解

圖例:

設計模式第六講-外觀模式

外觀不只是簡化了介面,也將客戶從元件的子系統中解耦. 外觀和介面卡可以包裝許多類,但是外觀的意圖是簡化介面,而介面卡的意圖是將介面轉換成不同介面。

場景設定

似曾相識,有個超級複雜的論壇系統(客戶端呼叫的相當複雜)。

設計模式第六講-外觀模式

下面我們將直接看看舊程式碼怎麼寫的吧

UserController 主流程類

package facade;

public class UserController {

    public static void main(String[] args) {

        //獲取暱稱
        UserInfo userInfo = new UserInfo();
        String userName = userInfo.getNickName();

        //獲取最近登入時間
        UserSystem userSystem = new UserSystem();
        String lastLoginTime = userSystem.lastLoginTime();


        //獲取使用者點贊數
        UserBehavior userBehavior= new UserBehavior();
        int likeNum = userBehavior.getLikeNum();

        //todo
        //其它很多小類組成了供前端渲染的資料

        System.out.println("使用者名稱" + userName + ",最近登入時間" + lastLoginTime+",喜歡了"+likeNum+"篇帖子");
    }

}
複製程式碼

相關小類

使用者資訊相關

package facade;

public class UserInfo {

    public String getNickName(){
        return "許仙啊";
    }
}
複製程式碼

使用者系統相關:

package facade;

import java.text.SimpleDateFormat;
import java.util.Date;

public class UserSystem {

    public String lastLoginTime() {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return df.format(new Date());
    }
}
複製程式碼

使用者行為相關:

package facade;

public class UserBehavior {

    public int getLikeNum() {
        return 5;
    }
}

複製程式碼

output:

使用者名稱許仙啊,最近登入時間2019-01-15 23:08:45,喜歡了5篇帖子
複製程式碼

由此結構我們可以看出,對於我們的控制器來說是比較複雜的,物件涉及的比較多,當業務比較越來越大的時候,很容易出現耦合,無法拆分,只能在控制器中另創方法.

外觀模式改造

核心-外觀物件

package facade;

public class Facade {

    //使用者資訊物件
    private UserInfo userInfo;

    //使用者系統資訊物件
    private UserSystem userSystem;

    //使用者行為物件
    private UserBehavior userBehavior;

    public Facade() {
        userInfo = new UserInfo();
        userSystem = new UserSystem();
        userBehavior = new UserBehavior();
    }

    public String getUserInfo() {

        String userName = userInfo.getNickName();

        String lastLoginTime = userSystem.lastLoginTime();

        int likeNum = userBehavior.getLikeNum();

        //todo
        //其它很多小類組成了供前端渲染的資料
        //可以按類別拆分到不同方法,也可以按功能需求一起,需要個人思考

        return "使用者名稱" + userName + ",最近登入時間" + lastLoginTime+",喜歡了"+likeNum+"篇帖子";

    }

}
複製程式碼

呼叫:

package facade;

public class UserController {

    public static void main(String[] args) {

        //外觀物件
        Facade facade = new Facade();
        System.out.println(facade.getUserInfo());

    }
}
複製程式碼

output:

使用者名稱許仙啊,最近登入時間2019-01-15 23:19:16,喜歡了5篇帖子
複製程式碼

UML圖(圖片來自網路)

設計模式第六講-外觀模式

我們由前置控制器移動到了getUserInfo方法中集體封裝了。可能感覺並沒有什麼好處,但是它完美的體現了依賴倒轉原則和迪米特法則的思想。

歸納總結

看到這裡相信你敢相信這也算設計模式.其實外觀模式有很多種靈活的拆分方式,對於封裝系統的複雜度、提供更好的小類小功能的管理還是有非常大的用處的。

上文提到了迪米特法則,指的是如果兩個類不必直接通訊,那麼這兩個類就不應當發生直接的相互作用.如果其中一個類需要呼叫另一個類的某一個方法的話,可以通過第三者轉發這個呼叫(此文的第三者指的就是我們的外觀類) --摘自《大話設計模式》

什麼時候應該使用呢

其實這是個層與層關係的問題,我們的控制器層和我們的系統實現層,隨著業務的複雜度上升,他們之間的關係也會越來越複雜.

增加外觀Facade層,對上層提供一個簡單的介面,可以減少他們的依賴.

當維護一個遺留大型系統的時候,很難再此基礎上擴充它難以維護下去,可能使用外觀模式是非常好的一個選擇。

設計模式第六講-外觀模式

最後談一下和介面卡模式的區別吧

區別是介面卡只是適配一個類,外觀模式作用多個類?

答案不對,介面卡可以適配多個類,外觀模式也可以只服務一個複雜的類.主要他們的意圖是不一樣的,

  • 介面卡模式的意圖是改變介面符合客戶的預期
  • 外觀模式的意圖是提供子系統的一個簡化介面.

參考《大話設計模式》 《Head First設計模式》

更多精彩內容關注公眾號,和最有熱心的小宇作者面對面 (可搜尋: 呆呆熊一點通)

設計模式第六講-外觀模式

相關文章