新谈设计模式 Chapter 10 — 外观模式 Facade

张开发
2026/4/10 19:48:37 15 分钟阅读

分享文章

新谈设计模式 Chapter 10 — 外观模式 Facade
Chapter 10 — 外观模式 Facade灵魂速记一键启动——你按一个按钮它帮你点火、调座椅、开空调、放音乐。秒懂类比启动一辆车发动机点火 → 变速箱切 D 档 → 仪表盘亮灯 → 安全系统自检 → 空调自动开。你不需要知道这些子系统的启动顺序和细节——你只需要拧钥匙按一键启动。Facade 就是那个一键启动按钮为复杂的子系统群提供一个简单的统一入口。问题引入// 灾难现场客户端直接操作一堆子系统voidrenderVideo(conststd::stringfilename){VideoFilefile(filename);autocodecCodecFactory::extract(file);autobufferBitrateReader::read(file,codec);autoresultBitrateReader::convert(buffer,mp4);AudioMixer mixer;autoaudiomixer.fix(result);FileWriter::write(output.mp4,result,audio);// 每个客户端都要写这一串……// 改了一个子系统的接口到处都要改}问题客户端和子系统紧耦合一堆细节暴露在外。模式结构┌────────────────────────────────────┐ │ Facade │ ← 简单的入口 │ convertVideo(file, format) │ └─────┬───────┬──────┬──────┬───────┘ │ │ │ │ ┌────┴──┐ ┌──┴───┐ ┌┴───┐ ┌┴──────┐ │Codec │ │Reader│ │Mixer│ │Writer │ ← 复杂子系统 │Factory│ │ │ │ │ │ │ └───────┘ └──────┘ └─────┘ └───────┘ 客户端只跟 Facade 说话不碰子系统。C 实现#includeiostream#includestring// 一堆复杂的子系统 classCPU{public:voidfreeze(){std::cout CPU: 冻结\n;}voidjump(longaddress){std::cout CPU: 跳转到地址 0xstd::hexaddressstd::dec\n;}voidexecute(){std::cout CPU: 执行指令\n;}};classMemory{public:voidload(longaddress,conststd::stringdata){std::cout 内存: 将 \data\ 加载到 0xstd::hexaddressstd::dec\n;}};classHardDrive{public:std::stringread(longsector,intsize){std::cout 硬盘: 读取扇区 sector (size bytes)\n;returnboot_data;}};classScreen{public:voidturnOn(){std::cout 屏幕: 点亮\n;}voiddisplay(conststd::stringcontent){std::cout 屏幕: 显示 \content\\n;}};// Facade一键开机 classComputerFacade{public:voidstart(){std::cout【一键开机】\n;screen_.turnOn();cpu_.freeze();autobootDatahdd_.read(0,1024);memory_.load(0x00100000,bootData);cpu_.jump(0x00100000);cpu_.execute();screen_.display(Welcome!);std::cout【开机完成】✅\n;}voidshutdown(){std::cout【一键关机】\n;screen_.display(Shutting down...);cpu_.freeze();std::cout【已关机】\n;}private:CPU cpu_;Memory memory_;HardDrive hdd_;Screen screen_;};intmain(){ComputerFacade computer;computer.start();std::cout\n;computer.shutdown();}输出【一键开机】 屏幕: 点亮 CPU: 冻结 硬盘: 读取扇区 0 (1024 bytes) 内存: 将 boot_data 加载到 0x100000 CPU: 跳转到地址 0x100000 CPU: 执行指令 屏幕: 显示 Welcome! 【开机完成】✅ 【一键关机】 屏幕: 显示 Shutting down... CPU: 冻结 【已关机】核心洞察Facade 不是封装不是限制——它是友好入口。子系统照样可以直接用Facade 只是提供了一条捷径。// 你当然可以直接操作子系统高级用户CPU cpu;cpu.freeze();cpu.execute();// 但大多数时候用 Facade 就够了普通用户ComputerFacade pc;pc.start();什么时候用✅ 适合❌ 别用子系统复杂客户端只需要常用功能子系统本来就简单想降低客户端和子系统的耦合每个客户端都需要不同的组合分层架构中对外提供简单 API需要暴露所有子系统细节给第三方库提供简单包装只有一个子系统防混淆Facade vs AdapterFacadeAdapter包装对象多个子系统一个不兼容的类目的简化复杂接口转换接口格式新接口定义全新的简化接口适配到已有接口一句话分清Facade 是我帮你搞定一切Adapter 是我帮你转个接口。Facade vs MediatorFacadeMediator通信方向单向客户端→子系统双向组件↔中介↔组件子系统知道 Facade?不知道组件知道中介者目的简化入口解耦组件间通信Facade vs ProxyFacadeProxy包装对象多个一个接口定义新的简化接口和原对象相同目的简化控制访问现实中的 Facade你每天都在用 Facade只是没意识到场景Facade背后的子系统jQuery$(selector)DOM、CSS、事件、AJAXstd::coutstd::cout x缓冲区、编码转换、设备IO编译器g main.cpp预处理、编译、汇编、链接手机一键清理一个按钮内存、缓存、进程管理Facade 的简洁哲学Facade 的设计原则 最少知识原则迪米特法则 ── 一个对象应该对其他对象有最少的了解 翻译成人话 ── 能不知道的事就别知道 ── 能不碰的子系统就别碰 ── 有人帮你搞定何必亲力亲为

更多文章