🧩 Facade Pattern
✅ Intent
- Hide complex internal processes and provide a simple interface to external callers
- Serve as a user-friendly "single entry point" to the system
✅ Motivation
- Allows use cases (e.g., order processing) to be invoked via a single external interface
- Keeps responsibilities separated while providing a unified point of access
✅ When to Use
- When business logic is modularized but should be accessed as a whole
- When you want to encapsulate a set of related operations into a single function call
✅ Code Example
- TypeScript
- PHP
- Python
// 個別責務のクラスたち
class DiscountCalculator {
static calculate(base: number, type: string): number {
switch (type) {
case "student":
return base * 0.8;
case "member":
return base * 0.9;
default:
return base;
}
}
}
class InventoryService {
static reduce(productIds: string[]) {
console.log(`在庫を ${productIds.length} 件分減らしました`);
}
}
class EmailService {
static send(email: string, message: string) {
console.log(`メールを ${email} に送信: ${message}`);
}
}
class OrderLogger {
static log(orderId: string) {
console.log(`注文ログを記録: ${orderId}`);
}
}
// Facadeクラス
class OrderProcessor {
constructor(
private productIds: string[],
private userEmail: string,
private discountType: string
) {}
confirmOrder() {
const basePrice = this.productIds.length * 1000;
const total = DiscountCalculator.calculate(basePrice, this.discountType);
InventoryService.reduce(this.productIds);
EmailService.send(
this.userEmail,
`ご注文が確定しました(合計: ¥${total})`
);
OrderLogger.log("order-" + Math.random().toString(36).substring(2));
}
}
// 利用例
const facadeProcessor = new OrderProcessor(
["p01", "p02"],
"hiroshi@example.com",
"student"
);
facadeProcessor.confirmOrder();
<?php
// 個別責務のクラスたち
class DiscountCalculator {
public static function calculate(float $base, string $type): float {
switch ($type) {
case "student":
return $base * 0.8;
case "member":
return $base * 0.9;
default:
return $base;
}
}
}
class InventoryService {
public static function reduce(array $productIds): void {
echo "在庫を " . count($productIds) . " 件分減らしました\\n";
}
}
class EmailService {
public static function send(string $email, string $message): void {
echo "メールを {$email} に送信: {$message}\\n";
}
}
class OrderLogger {
public static function log(string $orderId): void {
echo "注文ログを記録: {$orderId}\\n";
}
}
// Facadeクラス
class OrderProcessor {
public function __construct(
private array $productIds,
private string $userEmail,
private string $discountType
) {}
public function confirmOrder(): void {
$basePrice = count($this->productIds) * 1000;
$total = DiscountCalculator::calculate($basePrice, $this->discountType);
InventoryService::reduce($this->productIds);
EmailService::send($this->userEmail, "ご注文が確定しました(合計: ¥{$total})");
$orderId = "order-" . substr(md5((string)mt_rand()), 0, 8);
OrderLogger::log($orderId);
}
}
// 利用例
$processor = new OrderProcessor(
["p01", "p02"],
"hiroshi@example.com",
"student"
);
$processor->confirmOrder();
import random
import string
# 個別責務のクラスたち
class DiscountCalculator:
@staticmethod
def calculate(base: float, discount_type: str) -> float:
if discount_type == "student":
return base * 0.8
elif discount_type == "member":
return base * 0.9
return base
class InventoryService:
@staticmethod
def reduce(product_ids: list[str]):
print(f"在庫を {len(product_ids)} 件分減らしました")
class EmailService:
@staticmethod
def send(email: str, message: str):
print(f"メールを {email} に送信: {message}")
class OrderLogger:
@staticmethod
def log(order_id: str):
print(f"注文ログを記録: {order_id}")
# Facadeクラス
class OrderProcessor:
def __init__(self, product_ids: list[str], user_email: str, discount_type: str):
self.product_ids = product_ids
self.user_email = user_email
self.discount_type = discount_type
def confirm_order(self):
base_price = len(self.product_ids) * 1000
total = DiscountCalculator.calculate(base_price, self.discount_type)
InventoryService.reduce(self.product_ids)
EmailService.send(self.user_email, f"ご注文が確定しました(合計: ¥{total})")
order_id = "order-" + ''.join(random.choices(string.ascii_lowercase + string.digits, k=8))
OrderLogger.log(order_id)
# 利用例
processor = OrderProcessor(
["p01", "p02"],
"hiroshi@example.com",
"student"
)
processor.confirm_order()
✅ Explanation
This code applies the Facade
pattern to hide the complex internal logic involved in order processing, exposing a simplified interface (OrderProcessor
) to external callers.
The Facade
pattern provides a "gateway" to a complex subsystem, allowing clients to interact with it in a streamlined manner.
1. Overview of the Facade Pattern
In this implementation, the OrderProcessor
class acts as the Facade
, coordinating multiple classes with distinct responsibilities:
DiscountCalculator
: Responsible for calculating discountsInventoryService
: Responsible for inventory controlEmailService
: Responsible for sending emailsOrderLogger
: Responsible for logging order activities
2. Key Classes and Their Roles
-
DiscountCalculator
- A utility class that calculates discounts
- Computes the price based on the discount type (
student
,member
,default
)
-
InventoryService
- Handles the reduction of inventory stock
-
EmailService
- Sends messages to a specified email address
-
OrderLogger
- Records order logs
-
OrderProcessor
- The
Facade
class - Integrates the above subsystems and provides a simplified interface for order processing
- The
confirmOrder
method performs the following steps:- Calculates the base price
- Applies discounts to compute the total amount
- Updates the inventory
- Sends a confirmation email
- Logs the order
- The
3. UML Class Diagram
4. Benefits of the Facade Pattern
- Simplified Interface: External clients can complete the entire order process by interacting only with
OrderProcessor
- Separation of Concerns: Each class has a single, well-defined responsibility, improving maintainability
- Reusability: The underlying subsystems (
DiscountCalculator
, etc.) are decoupled and can be reused independently
This design effectively encapsulates complexity while maintaining clear separation of responsibilities among classes.