簡介
外觀模式(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設計模式》
更多精彩內容關注公眾號,和最有熱心的小宇作者面對面 (可搜尋: 呆呆熊一點通)