Skip to content

外观模式(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: Ready

2.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();

七、全文总结

外观模式的核心是 为复杂子系统提供统一简化接口,降低使用门槛

核心要点

  1. 外观不封装子系统,只提供简化入口
  2. 适用于复杂子系统简化、分层架构、第三方库封装
  3. 按功能拆分外观,避免上帝类
  4. 可暴露子系统供高级用户直接使用
  5. 可与单例、多层外观结合使用