外觀模式(Facade Pattern)

Facade 外觀模式

外觀模式(Facade Pattern)是一種結構型設計模式,它為子系統提供一組統一的接口。這個接口使子系統更容易使用。
以現實的例子做舉例,很像我們打電話給客服,客服會幫我們處理我們的問題,而我們不需要知道客服是如何處理的,只需要知道我們的問題被解決了。
https://refactoring.guru/images/patterns/diagrams/facade/live-example-en.png?id=461900f9fbacdd0ce981dcd24e121078

結構

https://refactoring.guru/images/patterns/diagrams/facade/structure.png?id=461900f9fbacdd0ce981dcd24e121078

  • Facade: 提供統一的接口,並且知道如何將請求傳遞給子系統的相應對象。
  • Additional Facade: 可以有多個外觀,這取決於系統的複雜性。
  • subsystem: 這是子系統的一組類,它實現了子系統的功能。子系統並不知道外觀的存在。

範例

假設我們要設計一個「飯店預訂系統」,其需求包含:

  • 檢查房間是否可預訂
  • 預訂房間
  • 進行付款
  • 記錄與維護顧客資料

內部子系統可能包含:

  • RoomService:與房間相關的業務(檢查房間可用性、預訂、取消等)
  • PaymentService:與付款相關的業務(信用卡或其他支付方式)
  • CustomerService:與顧客資料維護相關

重構前

RoomService

1
2
3
4
5
6
7
8
9
10
11
12
public class RoomService {
public boolean isRoomAvailable(int roomNumber) {
// 假設進行各種內部檢查(已預訂狀態、維修狀態等)
System.out.println("Checking availability for room: " + roomNumber);
return true; // 簡化起見
}

public void bookRoom(int roomNumber) {
// 進行預訂流程
System.out.println("Booking room: " + roomNumber);
}
}

PaymentService

1
2
3
4
5
6
7
public class PaymentService {
public boolean pay(String customerName, double amount) {
// 假設進行實際的支付流程(信用卡、第三方支付等)
System.out.println("Paying " + amount + " for " + customerName);
return true; // 簡化起見
}
}

CustomerService

1
2
3
4
5
6
public class CustomerService {
public void addCustomer(String customerName, String contactInfo) {
// 新增顧客至系統
System.out.println("Adding customer: " + customerName);
}
}

客戶端程式(未使用外觀模式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ClientWithoutFacade {
public static void main(String[] args) {
String customerName = "Alice";
String contactInfo = "alice@example.com";
int roomNumber = 101;
double amount = 2000.0;

// 必須直接呼叫多個子系統
CustomerService customerService = new CustomerService();
customerService.addCustomer(customerName, contactInfo);

RoomService roomService = new RoomService();
boolean available = roomService.isRoomAvailable(roomNumber);
if (available) {
roomService.bookRoom(roomNumber);

PaymentService paymentService = new PaymentService();
boolean paymentSuccess = paymentService.pay(customerName, amount);
if (paymentSuccess) {
System.out.println("Room booked and payment successful!");
}
}
}
}

缺點

  • 客戶端必須了解並直接操作 CustomerService、RoomService、PaymentService 等多個類別。
  • 程式碼分散在客戶端,當要新增或修改預訂流程時,勢必會影響各個呼叫邏輯。
  • 耦合度高,客戶端需要了解不同子系統的順序、參數與各種細節。

重構後

HotelFacade

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class HotelFacade {
private CustomerService customerService;
private RoomService roomService;
private PaymentService paymentService;

public HotelFacade() {
this.customerService = new CustomerService();
this.roomService = new RoomService();
this.paymentService = new PaymentService();
}

/**
* 預訂飯店房間的統一介面
*/
public boolean bookHotel(String customerName, String contactInfo, int roomNumber, double amount) {
// 1. 新增顧客
customerService.addCustomer(customerName, contactInfo);

// 2. 檢查房間可用性
if (roomService.isRoomAvailable(roomNumber)) {
// 3. 預訂房間
roomService.bookRoom(roomNumber);
// 4. 進行付款
boolean paymentSuccess = paymentService.pay(customerName, amount);
if (paymentSuccess) {
System.out.println("Book hotel and payment successful!");
return true;
}
}
System.out.println("Booking failed!");
return false;
}
}

客戶端程式(使用外觀模式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ClientWithFacade {
public static void main(String[] args) {
String customerName = "Alice";
String contactInfo = "alice@example.com";
int roomNumber = 101;
double amount = 2000.0;

// 客戶端只需要透過一個 Facade 進行呼叫
HotelFacade hotelFacade = new HotelFacade();
boolean result = hotelFacade.bookHotel(customerName, contactInfo, roomNumber, amount);
if (result) {
System.out.println("Enjoy your stay!");
} else {
System.out.println("Sorry, we could not book your room.");
}
}
}

優點

  • 客戶端只需要了解並操作 HotelFacade 這個統一介面,不需要了解內部子系統的細節。
  • 程式碼集中在 HotelFacade,當要新增或修改預訂流程時,只需要修改 HotelFacade 即可。
  • 降低耦合度,客戶端不需要了解不同子系統的順序、參數與各種細節
  • 提高了安全性,客戶端無法直接操作子系統。

外觀模式(Facade Pattern)
https://shengshengyang.github.io/2025/01/17/Facade/
作者
Dean Yang
發布於
2025年1月17日
許可協議