- Facade Pattern คืออะไร
- โครงสร้าง
- ตัวอย่าง Workshop: ระบบสั่งซื้อสินค้า
- ก่อนและหลังใช้ Facade
- ข้อดี
- ข้อควรระวัง
- Facade ต่างจาก Adapter อย่างไร
- เมื่อใดควรใช้
- สรุป
#Facade Pattern คืออะไร
Facade Pattern เป็น Structural Design Pattern ที่จัดเตรียมอินเทอร์เฟซระดับสูงเพียงจุดเดียวเพื่อเรียกใช้งานระบบย่อย (subsystems) ที่ซับซ้อน ช่วยให้โค้ดฝั่งผู้ใช้ (client) ไม่จำเป็นต้องทราบลำดับการทำงานภายในทั้งหมด
ตัวอย่างเช่น ระบบสั่งซื้อสินค้าอาจต้องตรวจสอบสต็อก ชำระเงิน และจัดส่งสินค้า Facade จะประสานงานขั้นตอนเหล่านี้ผ่านเมธอดเดียว เช่น placeOrder()
#โครงสร้าง
classDiagram
class Client
class OrderFacade {
+placeOrder(productId, amount) boolean
}
class InventoryService {
+isAvailable(productId) boolean
}
class PaymentService {
+charge(amount) boolean
}
class ShippingService {
+schedule(productId) void
}
Client --> OrderFacade
OrderFacade --> InventoryService
OrderFacade --> PaymentService
OrderFacade --> ShippingService
#ตัวอย่าง Workshop: ระบบสั่งซื้อสินค้า
ตัวอย่างต่อไปนี้ใช้ Java 17 ขึ้นไป โดยแยกคลาสเป็นไฟล์เดียวเพื่อทดลองได้ทันที
สร้างไฟล์ Main.java:
class InventoryService {
public boolean isAvailable(String productId) {
System.out.println("Checking inventory: " + productId);
return true;
}
}
class PaymentService {
public boolean charge(double amount) {
System.out.println("Charging payment: " + amount);
return true;
}
}
class ShippingService {
public void schedule(String productId) {
System.out.println("Scheduling shipping: " + productId);
}
}
class OrderFacade {
private final InventoryService inventory;
private final PaymentService payment;
private final ShippingService shipping;
public OrderFacade(InventoryService inventory,
PaymentService payment,
ShippingService shipping) {
this.inventory = inventory;
this.payment = payment;
this.shipping = shipping;
}
public boolean placeOrder(String productId, double amount) {
if (amount <= 0 || !inventory.isAvailable(productId)) {
return false;
}
if (!payment.charge(amount)) {
return false;
}
shipping.schedule(productId);
return true;
}
}
public class Main {
public static void main(String[] args) {
OrderFacade facade = new OrderFacade(
new InventoryService(),
new PaymentService(),
new ShippingService()
);
boolean success = facade.placeOrder("BOOK-001", 499.0);
System.out.println("Order success: " + success);
}
}
รันโปรแกรม:
javac Main.java
java Main
ผลลัพธ์:
Checking inventory: BOOK-001
Charging payment: 499.0
Scheduling shipping: BOOK-001
Order success: true
#ก่อนและหลังใช้ Facade
ก่อนใช้ Facade: Client เรียก InventoryService, PaymentService และ ShippingService เอง และต้องจัดการลำดับขั้นตอนทั้งหมด
หลังใช้ Facade: Client เรียก facade.placeOrder(...) เพียงจุดเดียว ทำให้โค้ดอ่านง่ายและลดการผูกติดกับระบบย่อย
#ข้อดี
- ลดความซับซ้อนของการเรียกใช้ระบบย่อย
- ลด coupling ระหว่าง client กับ subsystem
- รวม workflow ที่ใช้งานบ่อยไว้ในจุดเดียว
- ทดสอบการประสานงานได้ง่ายขึ้นเมื่อฉีด dependencies ผ่าน constructor
#ข้อควรระวัง
- Facade อาจขยายเป็น God Object หากรวมความรับผิดชอบมากเกินไป
- Facade ไม่ได้แทนที่ API ของระบบย่อยทั้งหมด Client ยังเรียก subsystem โดยตรงได้เมื่อจำเป็น
- ตัวอย่างนี้เป็นการจำลองเพื่อเรียนรู้: ระบบจริงควรมีการจัดการ transaction, การชำระเงินซ้ำ, ความล้มเหลวของการจัดส่ง และการชดเชยธุรกรรมอย่างเหมาะสม
#Facade ต่างจาก Adapter อย่างไร
| Pattern | วัตถุประสงค์ |
|---|---|
| Facade | ทำให้การใช้งานหลาย subsystem ง่ายขึ้นผ่านอินเทอร์เฟซระดับสูง |
| Adapter | แปลงอินเทอร์เฟซที่เข้ากันไม่ได้ให้ใช้งานร่วมกันได้ |
| Mediator | จัดระเบียบการสื่อสารระหว่างออบเจ็กต์หลายตัว |
#เมื่อใดควรใช้
ใช้ Facade เมื่อระบบมีขั้นตอนย่อยหลายส่วนและต้องการให้ client ใช้งานผ่าน API ที่กระชับ เช่น ระบบสั่งซื้อสินค้า ระบบส่งอีเมลพร้อมแนบไฟล์ ระบบประมวลผลวิดีโอ หรือการเรียกบริการหลายตัวใน backend
#สรุป
Facade Pattern ช่วยซ่อนความยุ่งยากของการประสานงาน subsystem และสร้างจุดเข้าถึงที่ใช้งานง่าย เหมาะกับ Java Application ที่ต้องการแยกส่วน client ออกจากรายละเอียดการทำงานภายใน โดยยังคงเปิดทางให้ใช้ subsystem โดยตรงได้เมื่อจำเป็น