外观模式的本质是封装交互、简化调用,它不扩展子系统功能,仅通过统一入口收拢分散调用,保持轻量无侵入,专注编排子系统协作并提供语义化接口。

外观模式的本质是封装而非继承
外观模式不是为了扩展子系统功能,而是把一堆分散的、耦合的调用逻辑收拢到一个统一入口。它不改变子系统内部结构,也不要求子系统配合改造——你只需写一个新类,把 SubSystemA、SubSystemB、SubSystemC 的实例创建和方法调用顺序组织起来就行。
常见错误是试图让外观类继承某个子系统类,或者强行把子系统改造成“支持外观”的接口。这违背初衷:外观本就是外部胶水层,应该保持轻量、无侵入。
- 外观类通常只持有一组子系统对象的引用,不暴露它们的细节
- 所有业务逻辑仍由子系统各自完成,外观只负责编排调用顺序和参数传递
- 如果子系统方法签名经常变,外观类会成为高频维护点——这是设计代价,不是 bug
如何写一个真正可用的 Facade 类
别一上来就抽象出 IFacade 接口或搞工厂模式。先写死具体依赖,验证流程通不通。比如你要整合日志记录、数据校验、数据库写入三步操作:
class OrderProcessingFacade:
def __init__(self):
self._validator = DataValidator()
self._logger = FileLogger()
self._db = DatabaseWriter()
def place_order(self, order_data: dict) -> bool:
if not self._validator.validate(order_data):
self._logger.log("Validation failed", order_data)
return False
try:
self._db.save(order_data)
self._logger.log("Order saved", order_data)
return True
except Exception as e:
self._logger.log("Save failed", {"error": str(e)})
return False
关键点:
立即学习“Python免费学习笔记(深入)”;
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
-
__init__里直接初始化子系统实例,避免每次调用都新建(除非有状态冲突) - 方法名要反映业务意图(如
place_order),而不是技术动作(如run_pipeline) - 异常不向上抛,由外观统一处理并返回语义化结果(
True/False或Result对象)
什么时候不该用 Facade
Facade 不是万能胶。当出现以下情况时,硬套外观反而增加复杂度:
- 子系统之间调用关系极简单,比如只有一个
api_client.send()调用 —— 直接用更清晰 - 不同业务场景需要完全不同的子系统组合(A+B+C vs A+D+E),此时应拆成多个外观类,而不是塞进一个大而全的
UniversalFacade - 子系统本身已提供高层 API(如
requests.Session封装了连接复用、重试、cookie 管理),再包一层只是徒增间接性
典型误用:JSONEncoderFacade 包裹 json.dumps 并加个默认参数——这种“封装”没有降低认知负担,反而让人多查一层。
测试 Facade 类的要点
Facade 的单元测试重点不是验证子系统行为,而是确认它是否按预期顺序调用了子系统方法,并正确处理了返回值和异常。
- 用
unittest.mock.Mock替换子系统依赖,检查mock_validator.validate.assert_called_once_with(...) - 模拟子系统失败(如
mock_db.save.side_effect = ConnectionError),验证外观是否捕获并返回合理结果 - 不要测
json.dumps是否能序列化 dict——那是json模块该测的
Facade 的复杂度藏在编排逻辑里,而不是子系统实现里。测错地方,等于白测。

















