模式定義與核心價值
外觀模式為子系統中的一組介面提供統一的高層介面,使子系統更容易使用。核心角色:
- Facade (外觀角色):客戶端調用入口,知曉子系統功能,委派請求。
- Subsystem (子系統角色):實現具體功能,對外觀無感知 (無依賴)。
- Client (客戶角色):通過外觀訪問子系統,不直接依賴子系統類。
經典案例:繪圖系統
// 子系統:各種形狀
interface Shape { void draw(); }
class Circle implements Shape { public void draw() { System.out.println("畫圓 ○"); } }
class Rectangle implements Shape { public void draw() { System.out.println("畫矩形 ▭"); } }
class Square implements Shape { public void draw() { System.out.println("畫正方形 □"); } }
// 外觀:統一繪圖入口
class ShapeMaker {
private final Shape circle = new Circle();
private final Shape rectangle = new Rectangle();
private final Shape square = new Square();
public void drawCircle() { circle.draw(); }
public void drawRectangle() { rectangle.draw(); }
public void drawSquare() { square.draw(); }
// 組合方法:一次繪製多種形狀
public void drawHouse() {
drawSquare(); // 房子主體
drawTriangle(); // 屋頂 (需擴展)
drawRectangle(); // 門
}
private void drawTriangle() { System.out.println("畫三角形 △"); }
}
// 客戶端
public class FacadeDemo {
public static void main(String[] args) {
ShapeMaker maker = new ShapeMaker();
maker.drawCircle();
maker.drawRectangle();
maker.drawSquare();
maker.drawHouse(); // 一鍵畫房子
}
}
另一實例:抽屜系統 (鏈式依賴)
class DrawerOne {
public void open() {
System.out.println("第一個抽屜打開");
getKey();
}
private void getKey() { System.out.println("獲得第二個抽屜鑰匙"); }
}
class DrawerTwo {
public void open() {
System.out.println("第二個抽屜打開");
getFile();
}
private void getFile() { System.out.println("獲得重要文件"); }
}
// 外觀:封裝複雜開啟流程
class DrawerFacade {
private final DrawerOne one = new DrawerOne();
private final DrawerTwo two = new DrawerTwo();
public void openAll() {
one.open();
two.open();
}
}
public class Client {
public static void main(String[] args) {
new DrawerFacade().openAll(); // 一鍵開啟所有
}
}
適用場景
| 場景 | 外觀模式價值 |
| 為複雜模塊提供簡單入口 | 降低客戶端學習成本、減少依賴 |
| 子系統相對獨立、穩定 | 外觀屏蔽變化、解耦 |
| 層級化架構 | 定義每層入口 (Controller → Facade → Service → DAO) |
| 遷移遗留系統 | 新系統通過外觀漸進式調用舊系統 |
與相關模式對比
| 模式 | 意圖 | 關鍵差異 |
| 外觀 | 簡化介面、解耦 | 單向:Client → Facade → Subsystem |
| 中介者 | 協調多對象交互 | 雙向:Colleague ↔ Mediator ↔ Colleague |
| 代理 | 控制對象訪問 | 同介面:Proxy 實現 Subject 介面 |
| 抽象工廠 | 創建對象族 | 關注創建、非使用 |
最佳實踐與避坑
- 外觀不應成為上帝類:只做委派/組合,不包含業務邏輯。
- 子系統類應保持 package-private 或內部類:強制客戶端通過外觀訪問。
- 可提供多個外觀:針對不同客戶群體 (如 AdminFacade、UserFacade)。
- 不要強行外觀:若客戶端本身需要精細控制子系統,直接依賴更清晰。
- Spring 應用中:Service 層常扮演 Facade 角色,整合多個 Repository/Client,Controller 僅調用 Service。
- 上一篇文章: Java 快速排序優化全攻略:從基礎實現到三向切分、尾遞歸消除
- 下一篇文章: 圖解快速排序:Java 實現 Partition 過程逐步演示
Copyright ©
程式碼之家 All Rights Reserved