外观模式:从家庭电源控制看“简化接口“的设计智慧

外观模式:从家庭电源控制看"简化接口"的设计智慧

一、什么是外观模式?------ 从"总控开关"说起

忙碌一天后准备入睡,若没有总控开关,你得起身逐个关闭运转的空调、亮着的台灯和播放新闻的电视,耗时又繁琐。而床头的"总控开关"只需轻轻一按,所有设备便一键关闭------这就是外观模式的核心逻辑。

外观模式(Facade Pattern)又称门面模式,是结构型设计模式的一种。它通过定义统一的高层接口,封装复杂子系统的交互逻辑,让客户端无需了解子系统内部细节,仅通过该接口就能操控整个系统。

就像餐厅服务员,你点一份双人套餐时,无需亲自对接后厨、吧台和仓库,服务员会协调各环节,将完整套餐送到你面前。外观模式就扮演这样的"服务员"角色,把客户端的简单需求拆解为子系统的具体操作,再反馈结果,不改变子系统功能,只简化交互方式。

二、外观模式的结构与UML图

外观模式结构简洁,靠两个核心角色配合实现"复杂系统简单化"。

1. 核心角色

  • 外观角色(Facade):客户端直接交互的"总接口",内部持有子系统引用。它一方面将客户端指令转化为子系统能理解的调用,另一方面可将多个子系统操作打包成复合功能,比如"关闭所有设备"就是空调、台灯、电视关闭操作的组合。
  • 子系统角色(Subsystem):实现具体功能的独立模块,像空调、台灯等,有自己的接口和逻辑,但从不主动与客户端交互,仅通过外观角色接收指令。

2. 通用UML图

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=E%3A\C%2B%2B体系\设计模式\设计模式笔记\资源图\外观模式.png\&pos_id=img-TdSTNDoX-![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/4b9a4bd1178a46dc996f636233ce83a2.png)

1766846369053)

说明:客户端所有请求都指向外观类,外观类按请求调用对应子系统。就像用手机拍照,无需了解摄像头、处理器等细节,点击快门即可。

3. 家庭电源控制场景的UML图

说明:main函数是客户端,PowerSwitchFacade是外观类。客户端输入指令(如1、2、3、4)调用外观类的control()方法,外观类再调用对应子系统方法。子系统还可扩展功能,外观类也能灵活组合操作。

三、代码实现:家庭电源总开关的外观模式设计

基于小明家场景(输入1-4关设备、5-8开设备、9观影模式、10阅读模式),用C++实现外观模式。

1. 子系统类:定义设备的具体功能

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>

// 空调子系统:支持开关和温度调节
class AirConditioner {
private:
    int temperature = 26; 
    bool isOn = false;    

public:
    void turnOn() {
        if (!isOn) {
            isOn = true;
            std::cout << "Air Conditioner is turned on. Current temperature: " << temperature << "°C" << std::endl;
        } else {
            std::cout << "Air Conditioner is already on." << std::endl;
        }
    }

    void turnOff() {
        if (isOn) {
            isOn = false;
            std::cout << "Air Conditioner is turned off." << std::endl;
        } else {
            std::cout << "Air Conditioner is already off." << std::endl;
        }
    }

    void setTemperature(int temp) {
        if (isOn) {
            if (temp >= 16 && temp <= 30) {
                temperature = temp;
                std::cout << "Air Conditioner temperature set to " << temperature << "°C" << std::endl;
            } else {
                std::cout << "Invalid temperature (16-30°C only)." << std::endl;
            }
        } else {
            std::cout << "Cannot set temperature: Air Conditioner is off." << std::endl;
        }
    }
};

// 台灯子系统:支持开关和亮度调节
class DeskLamp {
private:
    int brightness = 50; 
    bool isOn = false;   

public:
    void turnOn() {
        if (!isOn) {
            isOn = true;
            std::cout << "Desk Lamp is turned on. Brightness: " << brightness << "%" << std::endl;
        } else {
            std::cout << "Desk Lamp is already on." << std::endl;
        }
    }

    void turnOff() {
        if (isOn) {
            isOn = false;
            std::cout << "Desk Lamp is turned off." << std::endl;
        } else {
            std::cout << "Desk Lamp is already off." << std::endl;
        }
    }

    void setBrightness(int level) {
        if (isOn) {
            if (level >= 0 && level <= 100) {
                brightness = level;
                std::cout << "Desk Lamp brightness set to " << brightness << "%" << std::endl;
            } else {
                std::cout << "Invalid brightness (0-100 only)." << std::endl;
            }
        } else {
            std::cout << "Cannot set brightness: Desk Lamp is off." << std::endl;
        }
    }
};

// 电视子系统:支持开关和频道切换
class Television {
private:
    int channel = 1;    
    bool isOn = false;  

public:
    void turnOn() {
        if (!isOn) {
            isOn = true;
            std::cout << "Television is turned on. Current channel: " << channel << std::endl;
        } else {
            std::cout << "Television is already on." << std::endl;
        }
    }

    void turnOff() {
        if (isOn) {
            isOn = false;
            std::cout << "Television is turned off." << std::endl;
        } else {
            std::cout << "Television is already off." << std::endl;
        }
    }

    void changeChannel(int ch) {
        if (isOn) {
            if (ch >= 1 && ch <= 100) {
                channel = ch;
                std::cout << "Television channel changed to " << channel << std::endl;
            } else {
                std::cout << "Invalid channel (1-100 only)." << std::endl;
            }
        } else {
            std::cout << "Cannot change channel: Television is off." << std::endl;
        }
    }
};

2. 外观类:封装总开关的控制逻辑

cpp 复制代码
// 电源总开关(外观类)
class PowerSwitchFacade {
private:
    AirConditioner ac;
    DeskLamp lamp;
    Television tv;

public:
    void control(int code) {
        switch (code) {
            case 1: ac.turnOff(); break;
            case 2: lamp.turnOff(); break;
            case 3: tv.turnOff(); break;
            case 4: 
                ac.turnOff();
                lamp.turnOff();
                tv.turnOff();
                std::cout << "All devices are off." << std::endl;
                break;
            case 5: ac.turnOn(); break;
            case 6: lamp.turnOn(); break;
            case 7: tv.turnOn(); break;
            case 8: 
                ac.turnOn();
                lamp.turnOn();
                tv.turnOn();
                std::cout << "All devices are on." << std::endl;
                break;
            case 9: 
                tv.turnOn();
                lamp.turnOff();
                ac.turnOn();
                ac.setTemperature(24);
                std::cout << "Movie mode activated." << std::endl;
                break;
            case 10: 
                lamp.turnOn();
                lamp.setBrightness(80);
                tv.turnOff();
                std::cout << "Reading mode activated." << std::endl;
                break;
            default: std::cout << "Invalid code (1-10 only)." << std::endl;
        }
    }
};

3. 客户端:通过外观类完成操作

cpp 复制代码
int main() {
    std::cout << "=== Home Power Control System ===" << std::endl;
    std::cout << "Commands: 1-4(off), 5-8(on), 9(movie), 10(reading)" << std::endl;
    std::cout << "Enter number of operations: ";
    
    int n;
    std::cin >> n;  
    std::vector<int> codes(n);
    
    std::cout << "Enter commands (separated by space): ";
    for (int i = 0; i < n; i++) {
        std::cin >> codes[i];  
    }

    PowerSwitchFacade mainSwitch;
    std::cout << "\n=== Executing Commands ===" << std::endl;
    for (int code : codes) {
        mainSwitch.control(code);
    }

    return 0;
}

四、生活中的外观模式:无处不在的"简化接口"

外观模式在生活中随处可见,核心是用简单接口掩盖复杂流程。

  • 智能手机的"快捷控制中心":点击"WiFi图标",无需了解无线网卡驱动、路由器认证等;开启"热点",不用管移动网络、WiFi、密码验证模块的协调,一个开关就能搞定。
  • 网购平台的"一键下单":点击按钮后,库存检查、地址验证、支付、物流等子系统自动运作,用户无需关心各环节细节。
  • 汽车的"启动按钮":无需插入钥匙、拧动点火等步骤,按钮会协调钥匙验证、发动机启动、电子设备通电等子系统。
  • 银行ATM机:插入银行卡、输密码、选取款金额,背后的身份验证、账户查询、现金管理、交易记录等子系统自动处理,用户只需简单操作。

五、外观模式的价值与使用原则

1. 外观模式的核心价值

  • 降低认知成本:减少用户记忆负担,无需记住每个子系统的操作逻辑,如只需记住总控开关的使用。
  • 隔离系统变化:子系统迭代不影响客户端,符合"开闭原则",如空调升级后,只要接口不变,外观类和客户端无需修改。
  • 简化复杂流程:将多个操作组合成一个接口,减少客户端调用次数,如"观影模式"一键实现多个设备的协调操作。

2. 使用外观模式的注意事项

  • 避免外观类臃肿:按功能拆分外观,如"客厅设备外观"、"卧室设备外观",避免一个外观类负责所有子系统。
  • 保留子系统直接访问权:外观是简化接口,不是唯一接口,高级用户或维修人员可能需要直接操作子系统。
  • 平衡封装与灵活性:不过度封装,适当暴露子系统的高级功能,如空调的"定时关闭",满足不同需求。

参考资料

本文参考《大话设计模式》《Head First 设计模式》中对结构型设计模式的讲解,结合生活场景与代码案例进行通俗化解读,展现外观模式"简化接口"的设计智慧。

相关推荐
你的冰西瓜3 小时前
C++中的list容器详解
开发语言·c++·stl·list
Geoking.3 小时前
【UML】面向对象中类与类之间的关系详解
设计模式·uml
CC.GG6 小时前
【C++】哈希表的实现
java·c++·散列表
bkspiderx7 小时前
C++变量生命周期:从创建到销毁的完整旅程
c++·生命周期·作用域·变量生命周期
T0uken8 小时前
现代 C++ 项目的 CMake 工程组织
c++
H CHY9 小时前
C++代码
c语言·开发语言·数据结构·c++·算法·青少年编程
xiaolang_8616_wjl9 小时前
c++题目_传桶(改编于atcoder(题目:Heavy Buckets))
数据结构·c++·算法
小小8程序员9 小时前
除了 gcc/g++,还有哪些常用的 C/C++ 编译器?
c语言·开发语言·c++