外观模式(Facade)
前言
外观模式为复杂子系统提供一个统一的简化接口。它不封装子系统,而是提供一个更高层的接口,降低客户端与子系统之间的耦合。本文将详细讲解外观模式的核心原理及实际应用。
一、核心概念
1.1 定义
为子系统中的一组接口提供一个一致的界面。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
1.2 核心角色
| 角色 | 说明 |
|---|---|
| 外观(Facade) | 提供简化接口的统一入口 |
| 子系统(Subsystems) | 复杂的内部组件 |
| 客户端(Client) | 通过外观使用子系统 |
二、代码实现
2.1 基础实现
php
<?php
// 子系统 A
class SubsystemA
{
public function operationA(): string
{
return "SubsystemA: Ready";
}
}
// 子系统 B
class SubsystemB
{
public function operationB(): string
{
return "SubsystemB: Ready";
}
}
// 子系统 C
class SubsystemC
{
public function operationC(): string
{
return "SubsystemC: Ready";
}
}
// 外观类:简化子系统接口
class Facade
{
private SubsystemA $subsystemA;
private SubsystemB $subsystemB;
private SubsystemC $subsystemC;
public function __construct()
{
$this->subsystemA = new SubsystemA();
$this->subsystemB = new SubsystemB();
$this->subsystemC = new SubsystemC();
}
// 简化操作:一键调用多个子系统
public function operation(): string
{
$results = [
$this->subsystemA->operationA(),
$this->subsystemB->operationB(),
$this->subsystemC->operationC(),
];
return "Facade:\n " . implode("\n ", $results);
}
}
// 客户端:只需与外观交互
$facade = new Facade();
echo $facade->operation() . PHP_EOL;
// Facade:
// SubsystemA: Ready
// SubsystemB: Ready
// SubsystemC: Ready2.2 实际案例:电脑启动
php
<?php
// CPU 子系统
class CPU
{
public function freeze(): void
{
echo "CPU: Freezing..." . PHP_EOL;
}
public function jump(int $address): void
{
echo "CPU: Jumping to {$address}" . PHP_EOL;
}
public function execute(): void
{
echo "CPU: Executing" . PHP_EOL;
}
}
// 内存子系统
class Memory
{
public function load(int $address, string $data): void
{
echo "Memory: Loading {$data} from {$address}" . PHP_EOL;
}
}
// 硬盘子系统
class HardDrive
{
public function read(int $lba, int $size): string
{
echo "HardDrive: Reading {$size} bytes from {$lba}" . PHP_EOL;
return "boot_data";
}
}
// 电源子系统
class PowerSupply
{
public function turnOn(): void
{
echo "PowerSupply: Turning on" . PHP_EOL;
}
public function turnOff(): void
{
echo "PowerSupply: Turning off" . PHP_EOL;
}
}
// 电脑外观:简化启动流程
class ComputerFacade
{
private CPU $cpu;
private Memory $memory;
private HardDrive $hardDrive;
private PowerSupply $power;
private const BOOT_ADDRESS = 0x0001;
private const BOOT_SECTOR = 0;
private const SECTOR_SIZE = 1024;
public function __construct()
{
$this->cpu = new CPU();
$this->memory = new Memory();
$this->hardDrive = new HardDrive();
$this->power = new PowerSupply();
}
// 一键启动
public function start(): void
{
echo "=== Computer Starting ===" . PHP_EOL;
$this->power->turnOn();
$this->cpu->freeze();
$data = $this->hardDrive->read(self::BOOT_SECTOR, self::SECTOR_SIZE);
$this->memory->load(self::BOOT_ADDRESS, $data);
$this->cpu->jump(self::BOOT_ADDRESS);
$this->cpu->execute();
echo "=== Computer Started ===" . PHP_EOL . PHP_EOL;
}
// 一键关机
public function shutdown(): void
{
echo "=== Computer Shutting Down ===" . PHP_EOL;
$this->cpu->freeze();
$this->power->turnOff();
echo "=== Computer Off ===" . PHP_EOL . PHP_EOL;
}
}
// 客户端:一行代码启动电脑
$computer = new ComputerFacade();
$computer->start();
$computer->shutdown();2.3 实际案例:支付系统
php
<?php
// 子系统:用户验证
class UserValidator
{
public function validate(string $userId): bool
{
echo "Validating user: {$userId}" . PHP_EOL;
return true;
}
}
// 子系统:库存检查
class InventoryChecker
{
public function check(string $productId, int $quantity): bool
{
echo "Checking inventory: {$productId} x{$quantity}" . PHP_EOL;
return true;
}
}
// 子系统:支付处理
class PaymentProcessor
{
public function process(float $amount, string $method): bool
{
echo "Processing payment: \${$amount} via {$method}" . PHP_EOL;
return true;
}
}
// 子系统:订单创建
class OrderManager
{
public function create(string $userId, string $productId, int $quantity): string
{
$orderId = "ORD-" . time();
echo "Order created: {$orderId}" . PHP_EOL;
return $orderId;
}
}
// 子系统:通知
class NotificationService
{
public function send(string $userId, string $message): void
{
echo "Notifying {$userId}: {$message}" . PHP_EOL;
}
}
// 支付外观:简化下单流程
class CheckoutFacade
{
private UserValidator $validator;
private InventoryChecker $inventory;
private PaymentProcessor $payment;
private OrderManager $order;
private NotificationService $notification;
public function __construct()
{
$this->validator = new UserValidator();
$this->inventory = new InventoryChecker();
$this->payment = new PaymentProcessor();
$this->order = new OrderManager();
$this->notification = new NotificationService();
}
// 一键下单
public function checkout(
string $userId,
string $productId,
int $quantity,
float $amount,
string $method
): ?string {
// 1. 验证用户
if (!$this->validator->validate($userId)) {
echo "Checkout failed: Invalid user" . PHP_EOL;
return null;
}
// 2. 检查库存
if (!$this->inventory->check($productId, $quantity)) {
echo "Checkout failed: Out of stock" . PHP_EOL;
return null;
}
// 3. 处理支付
if (!$this->payment->process($amount, $method)) {
echo "Checkout failed: Payment failed" . PHP_EOL;
return null;
}
// 4. 创建订单
$orderId = $this->order->create($userId, $productId, $quantity);
// 5. 发送通知
$this->notification->send($userId, "Your order {$orderId} has been placed!");
return $orderId;
}
}
// 客户端:一行代码完成下单
$checkout = new CheckoutFacade();
$orderId = $checkout->checkout("user123", "prod456", 2, 100, "credit_card");
echo "Order ID: {$orderId}" . PHP_EOL;三、适用场景
| 场景 | 说明 |
|---|---|
| 复杂子系统简化 | 提供统一入口 |
| 分层架构 | 层与层之间通过外观通信 |
| 第三方库封装 | 简化库的使用 |
| 遗留系统 | 包装旧系统接口 |
| 微服务网关 | API Gateway 模式 |
四、优缺点分析
| 优点 | 缺点 |
|---|---|
| 简化客户端使用 | 可能成为上帝类 |
| 降低耦合度 | 外观可能隐藏重要细节 |
| 提高可维护性 | 需要维护外观类 |
| 分层隔离 | 违反开闭原则(新增功能需改外观) |
| 提供统一入口 | 子系统变更可能影响外观 |
五、常见踩坑与问题排查
5.1 外观变成上帝类
php
<?php
// 问题:外观类承担过多职责
class GodFacade
{
// 数百个方法
}
// 解决:按功能拆分多个外观
class OrderFacade
{
/* 订单相关 */
}
class UserFacade
{
/* 用户相关 */
}
class PaymentFacade
{
/* 支付相关 */
}5.2 完全屏蔽子系统
php
<?php
// 问题:客户端有时需要直接访问子系统的特定功能
// 解决:外观提供简化入口,但不禁止直接访问子系统
class FlexibleFacade
{
private PaymentProcessor $payment;
// 简化接口
public function quickCheckout(): void
{
/* ... */
}
// 暴露子系统,供高级用户使用
public function getPaymentProcessor(): PaymentProcessor
{
return $this->payment;
}
}六、优化方案与进阶
6.1 多层外观
php
<?php
// 底层外观:子系统组合
class DataFacade
{
public function fetchData(): string
{
/* ... */
return '';
}
public function saveData(string $data): void
{
/* ... */
}
}
// 高层外观:业务逻辑
class BusinessFacade
{
private DataFacade $dataFacade;
public function __construct()
{
$this->dataFacade = new DataFacade();
}
public function processOrder(): void
{
$data = $this->dataFacade->fetchData();
// 业务处理
$this->dataFacade->saveData($data);
}
}6.2 与单例结合
php
<?php
class SingletonFacade
{
private static ?SingletonFacade $instance = null;
private function __construct() {}
public static function getInstance(): SingletonFacade
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function operation(): void
{
/* ... */
}
}
// 全局使用
SingletonFacade::getInstance()->operation();七、全文总结
外观模式的核心是 为复杂子系统提供统一简化接口,降低使用门槛。
核心要点:
- 外观不封装子系统,只提供简化入口
- 适用于复杂子系统简化、分层架构、第三方库封装
- 按功能拆分外观,避免上帝类
- 可暴露子系统供高级用户直接使用
- 可与单例、多层外观结合使用
