🚪 外观模式 (Facade Pattern)
🎯 模式概述
外观模式是一种结构型设计模式,它为复杂的子系统提供一个简化的接口。就像酒店的前台一样,客人不需要直接与清洁部、厨房、维修部等各个部门打交道,只需要通过前台就能享受各种服务。
外观模式隐藏了系统的复杂性,为客户端提供了一个简单易用的接口。它不会封装子系统,而是提供一个更高层次的接口,使子系统更容易使用。
🔍 核心思想
外观模式通过引入一个外观类,将客户端与复杂的子系统解耦。客户端只需要与外观类交互,外观类负责调用相应的子系统完成工作。
📊 UML类图结构
外观模式 UML
┌─────────────────┐
│ Client │
│ │
│ + doSomething() │
└─────────────────┘
│
│ uses
▼
┌─────────────────┐
│ Facade │
│ │
│ - subsystem1: │
│ SubSystem1* │
│ - subsystem2: │
│ SubSystem2* │
│ - subsystem3: │
│ SubSystem3* │
│ │
│ + operation1() │
│ + operation2() │
│ + complexOp() │
└─────────────────┘
│
│ manages
▼
┌─────────────────┐
│ SubSystem1 │
│ │
│ + method1A() │
│ + method1B() │
└─────────────────┘
┌─────────────────┐
│ SubSystem2 │
│ │
│ + method2A() │
│ + method2B() │
│ + method2C() │
└─────────────────┘
┌─────────────────┐
│ SubSystem3 │
│ │
│ + method3A() │
│ + method3B() │
└─────────────────┘
🔍 关键点:Facade封装了复杂子系统的调用,为客户端提供简单接口
外观模式交互示意
Without Facade: With Facade:
Client Client
│ │
├─► SubSystem1.method1A() └─► Facade.complexOperation()
│ │
├─► SubSystem1.method1B() ├─► SubSystem1.method1A()
│ │
├─► SubSystem2.method2A() ├─► SubSystem1.method1B()
│ │
├─► SubSystem2.method2C() ├─► SubSystem2.method2A()
│ │
├─► SubSystem3.method3A() ├─► SubSystem2.method2C()
│ │
└─► SubSystem3.method3B() ├─► SubSystem3.method3A()
│
└─► SubSystem3.method3B()
🔍 外观模式大大简化了客户端的使用复杂度
🤔 为什么需要外观模式?
📊 问题场景对比
问题场景 | 不使用外观模式 | 使用外观模式 |
---|---|---|
🔧 复杂调用流程 | 客户端需了解详细步骤 | 一个方法完成所有操作 |
📚 学习成本 | 需要学习多个子系统 | 只需学习外观接口 |
🔄 维护难度 | 调用代码分散各处 | 统一在外观类中维护 |
🎯 错误处理 | 每个调用点都要处理 | 外观类统一处理错误 |
💡 问题演示
// ❌ 不使用外观模式的复杂调用
void clientCodeWithoutFacade() {
// 客户端需要了解复杂的调用序列
CPU cpu;
Memory memory;
HardDisk hardDisk;
// 启动计算机需要复杂的步骤
cpu.freeze();
memory.load(BOOT_ADDRESS, hardDisk.read(BOOT_SECTOR, SECTOR_SIZE));
cpu.jump(BOOT_ADDRESS);
cpu.execute();
// 如果步骤错误或遗漏,系统就无法正常工作
// 而且每个使用的地方都要重复这些复杂的调用
}
🚪 外观模式实现方式
1️⃣ 经典外观模式实现
让我们用家庭影院系统来演示外观模式:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
// 子系统1:音响系统
class AudioSystem {
private:
int volume = 50;
std::string audioMode = "Stereo";
bool isPoweredOn = false;
public:
void powerOn() {
isPoweredOn = true;
std::cout << "🔊 音响系统: 开机" << std::endl;
std::cout << " ├─ 自检中..." << std::endl;
std::cout << " └─ 音响系统就绪" << std::endl;
}
void powerOff() {
isPoweredOn = false;
std::cout << "🔊 音响系统: 关机" << std::endl;
}
void setVolume(int vol) {
if (isPoweredOn) {
volume = std::max(0, std::min(100, vol));
std::cout << "🔊 音响系统: 音量设置为 " << volume << std::endl;
} else {
std::cout << "⚠️ 音响系统: 请先开机" << std::endl;
}
}
void setAudioMode(const std::string& mode) {
if (isPoweredOn) {
audioMode = mode;
std::cout << "🔊 音响系统: 音效模式设置为 " << audioMode << std::endl;
}
}
void playTestSound() {
if (isPoweredOn) {
std::cout << "🔊 音响系统: 播放测试音频 ♪♫♪" << std::endl;
}
}
bool isOn() const {
return isPoweredOn; }
int getVolume() const {
return volume; }
};
// 子系统2:投影仪系统
class ProjectorSystem {
private:
bool isPoweredOn = false;
std::string resolution = "1920x1080";
int brightness = 80;
std::string inputSource = "HDMI1";
public:
void powerOn() {
isPoweredOn = true;
std::cout << "📽️ 投影仪: 开机" << std::endl;
std::cout << " ├─ 灯泡预热中..." << std::endl;
std::cout << " ├─ 镜头对焦中..." << std::endl;
std::cout << " └─ 投影仪就绪" << std::endl;
}
void powerOff() {
if (isPoweredOn) {
std::cout << "📽️ 投影仪: 关机" << std::endl;
std::cout << " └─ 灯泡冷却中..." << std::endl;
isPoweredOn = false;
}
}
void setResolution(const std::string& res) {
if (isPoweredOn) {
resolution = res;
std::cout << "📽️ 投影仪: 分辨率设置为 " << resolution << std::endl;
}
}
void setBrightness(int bright) {
if (isPoweredOn) {
brightness = std::max(1, std::min(100, bright));
std::cout << "📽️ 投影仪: 亮度设置为 " << brightness << "%" << std::endl;
}
}
void setInputSource(const std::string& source) {
if (isPoweredOn) {
inputSource = source;
std::cout << "📽️ 投影仪: 输入源切换到 " << inputSource << std::endl;
}
}
void displayTestPattern() {
if (isPoweredOn) {
std::cout << "📽️ 投影仪: 显示测试图案 ▓▓▓░░░▓▓▓" << std::endl;
}
}
bool isOn() const {
return isPoweredOn; }
};
// 子系统3:灯光控制系统
class LightingSystem {
private:
struct Light {
std::string name;
bool isOn;
int brightness;
std::string color;
Light(const std::string& n) : name(n), isOn(false), brightness(100), color("白色") {
}
};
std::vector<Light> lights;
std::string currentScene = "Normal";
public:
LightingSystem() {
lights.emplace_back("主灯");
lights.emplace_back("环境灯");
lights.emplace_back("装饰灯");
lights.emplace_back("走廊灯");
}
void turnOnAllLights() {
std::cout << "💡 灯光系统: 开启所有灯光" << std::endl;
for (auto& light : lights) {
light.isOn = true;
std::cout << " ├─ " << light.name << " 开启" << std::endl;
}
}
void turnOffAllLights() {
std::cout << "💡 灯光系统: 关闭所有灯光" << std::endl;
for (auto& light : lights) {
light.isOn = false;
std::cout << " ├─ " << light.name << " 关闭" << std::endl;
}
}
void setScene(const std::string& scene) {
currentScene = scene;
std::cout << "💡 灯光系统: 切换到 " << scene << " 模式" << std::endl;
if (scene == "Movie") {
// 电影模式:调暗灯光
for (auto& light : lights) {
if (light.name == "主灯") {
light.isOn = false;
std::cout << " ├─ " << light.name << " 关闭" << std::endl;
} else {
light.isOn = true;
light.brightness = 20;
light.color = "暖黄色";
std::cout << " ├─ " << light.name << " 调至 " << light.brightness
<< "% " << light.color << std::endl;
}
}
} else if (scene == "Party") {
// 聚会模式:彩色灯光
for (auto& light : lights) {
light.isOn = true;
light.brightness = 80;
light.color = "彩色";
std::cout << " ├─ " << light.name << " 调至 " << light.brightness
<< "% " << light.color << std::endl;
}
}
}
void dimLights(int level) {
std::cout << "💡 灯光系统: 调光至 " << level << "%" << std::endl;
for (auto& light : lights) {
if (light.isOn) {
light.brightness = level;
}
}
}
std::string getCurrentScene() const {
return currentScene; }
};
// 子系统4:窗帘控制系统
class CurtainSystem {
private:
bool isMotorized = true;
int openLevel = 100; // 0=完全关闭, 100=完全打开
std::string curtainType = "遮光窗帘";
public:
void openCurtains() {
if (isMotorized) {
std::cout << "🪟 窗帘系统: 自动打开窗帘" << std::endl;
std::cout << " ├─ 电机启动..." << std::endl;
openLevel = 100;
std::cout << " └─ 窗帘完全打开" << std::endl;
} else {
std::cout << "🪟 窗帘系统: 请手动打开窗帘" << std::endl;
}
}
void closeCurtains() {
if (isMotorized) {
std::cout << "🪟 窗帘系统: 自动关闭窗帘" << std::endl;
std::cout << " ├─ 电机启动..." << std::endl;
openLevel = 0;
std::cout << " └─ 窗帘完全关闭" << std::endl;
}
}
void setCurtainLevel(int level) {
if (isMotorized) {
openLevel = std::max(0, std::min(100, level));
std::cout << "🪟 窗帘系统: 窗帘开启度设置为 " << openLevel << "%" << std::endl;
}
}
int getOpenLevel() const {
return openLevel; }
};
// 子系统5:空调系统
class AirConditioningSystem {
private:
bool isPoweredOn = false;
int temperature = 25;
std::string mode = "Auto";
int fanSpeed = 2;
public:
void powerOn() {
isPoweredOn = true;
std::cout << "❄️ 空调系统: 开机" << std::endl;
std::cout << " ├─ 压缩机启动..." << std::endl;
std::cout << " └─ 空调系统就绪" << std::endl;
}
void powerOff() {
isPoweredOn = false;
std::cout << "❄️ 空调系统: 关机" << std::endl;
}
void setTemperature(int temp) {
if (isPoweredOn) {
temperature = std::max(16, std::min(30, temp));
std::cout << "❄️ 空调系统: 温度设置为 " << temperature << "°C" << std::endl;
}
}
void setMode(const std::string& m) {
if (isPoweredOn) {
mode = m;
std::cout << "❄️ 空调系统: 模式设置为 " << mode << std::endl;
}
}
void setFanSpeed(int speed) {
if (isPoweredOn) {
fanSpeed = std::max(1, std::min(5, speed));
std::cout << "❄️ 空调系统: 风速设置为 " << fanSpeed << " 档" << std::endl;
}
}
bool isOn() const {
return isPoweredOn; }
int getTemperature() const {
return temperature; }
};
// 外观类:家庭影院系统
class HomeTheaterFacade {
private:
std::unique_ptr<AudioSystem> audioSystem;
std::unique_ptr<ProjectorSystem> projectorSystem;
std::unique_ptr<LightingSystem> lightingSystem;
std::unique_ptr<CurtainSystem> curtainSystem;
std::unique_ptr<AirConditioningSystem> acSystem;
bool isSystemReady = false;
public:
HomeTheaterFacade() {
std::cout << "🏠 家庭影院系统: 初始化中..." << std::endl;
audioSystem = std::make_unique<AudioSystem>();
projectorSystem = std::make_unique<ProjectorSystem>();
lightingSystem = std::make_unique<LightingSystem>();
curtainSystem = std::make_unique<CurtainSystem>();
acSystem = std::make_unique<AirConditioningSystem>();
std::cout << "🏠 家庭影院系统: 初始化完成" << std::endl;
}
// 简单接口:开始观影
void startMovie(const std::string& movieTitle = "Unknown Movie") {
std::cout << "\n🎬 开始观影: " << movieTitle << std::endl;
std::cout << std::string(50, '=') << std::endl;
// 复杂的启动序列,客户端无需了解
std::cout << "正在准备观影环境..." << std::endl;
// 1. 关闭窗帘
curtainSystem->closeCurtains();
// 2. 设置灯光为电影模式
lightingSystem->setScene("Movie");
// 3. 启动投影仪
projectorSystem->powerOn();
projectorSystem->setInputSource("HDMI1");
projectorSystem->setResolution("4K");
projectorSystem->setBrightness(85);
// 4. 启动音响系统
audioSystem->