外观模式(Facade Pattern)是一种结构型设计模式,它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易被使用。这种模式通过引入一个外观角色来简化客户端与子系统之间的交互,客户端只需与外观角色打交道,而无需了解子系统内部的复杂结构。

外观模式的核心角色

  1. 外观(Facade):提供一个统一的接口,封装子系统的复杂性
  2. 子系统(Subsystem):由多个相关联的类组成,实现具体功能
  3. 客户端(Client):通过外观接口与子系统交互,无需了解子系统细节

外观模式的实现示例

下面以"家庭影院系统"为例展示外观模式的实现,家庭影院包含投影仪、音响、DVD播放器等多个设备,外观模式可以简化这些设备的协同操作:

#include <iostream>
#include <string>

// 子系统:投影仪
class Projector {
public:
    void on() {
        std::cout << "投影仪已开启" << std::endl;
    }

    void off() {
        std::cout << "投影仪已关闭" << std::endl;
    }

    void setInput(const std::string& source) {
        std::cout << "投影仪输入源设置为: " << source << std::endl;
    }

    void setResolution(const std::string& resolution) {
        std::cout << "投影仪分辨率设置为: " << resolution << std::endl;
    }
};

// 子系统:音响
class SoundSystem {
public:
    void on() {
        std::cout << "音响系统已开启" << std::endl;
    }

    void off() {
        std::cout << "音响系统已关闭" << std::endl;
    }

    void setVolume(int level) {
        std::cout << "音响音量设置为: " << level << std::endl;
    }

    void setSurroundSound(bool enable) {
        if (enable) {
            std::cout << "环绕声已开启" << std::endl;
        } else {
            std::cout << "环绕声已关闭" << std::endl;
        }
    }
};

// 子系统:DVD播放器
class DvdPlayer {
private:
    std::string currentMovie;

public:
    void on() {
        std::cout << "DVD播放器已开启" << std::endl;
    }

    void off() {
        std::cout << "DVD播放器已关闭" << std::endl;
    }

    void play(const std::string& movie) {
        currentMovie = movie;
        std::cout << "正在播放电影: " << currentMovie << std::endl;
    }

    void pause() {
        std::cout << "电影 " << currentMovie << " 已暂停" << std::endl;
    }

    void stop() {
        std::cout << "电影 " << currentMovie << " 已停止" << std::endl;
    }
};

// 外观类:家庭影院外观
class HomeTheaterFacade {
private:
    Projector* projector;
    SoundSystem* soundSystem;
    DvdPlayer* dvdPlayer;

public:
    // 初始化所有子系统
    HomeTheaterFacade(Projector* p, SoundSystem* s, DvdPlayer* d)
        : projector(p), soundSystem(s), dvdPlayer(d) {}

    // 简化接口:准备播放电影
    void watchMovie(const std::string& movie) {
        std::cout << "\n=== 准备播放电影 ===" << std::endl;
        projector->on();
        projector->setInput("DVD");
        projector->setResolution("4K");
        
        soundSystem->on();
        soundSystem->setVolume(8);
        soundSystem->setSurroundSound(true);
        
        dvdPlayer->on();
        dvdPlayer->play(movie);
    }

    // 简化接口:暂停电影
    void pauseMovie() {
        std::cout << "\n=== 暂停电影 ===" << std::endl;
        dvdPlayer->pause();
    }

    // 简化接口:结束电影
    void endMovie() {
        std::cout << "\n=== 结束电影 ===" << std::endl;
        dvdPlayer->stop();
        dvdPlayer->off();
        
        soundSystem->off();
        
        projector->off();
    }
};

// 客户端使用
int main() {
    // 创建子系统对象
    Projector* projector = new Projector();
    SoundSystem* soundSystem = new SoundSystem();
    DvdPlayer* dvdPlayer = new DvdPlayer();

    // 创建外观对象
    HomeTheaterFacade* homeTheater = new HomeTheaterFacade(projector, soundSystem, dvdPlayer);

    // 客户端通过外观接口操作复杂的子系统
    homeTheater->watchMovie("星际穿越");
    homeTheater->pauseMovie();
    homeTheater->watchMovie("星际穿越");  // 继续播放
    homeTheater->endMovie();

    // 清理资源
    delete homeTheater;
    delete dvdPlayer;
    delete soundSystem;
    delete projector;

    return 0;
}

外观模式的工作原理

  1. 外观类封装了多个子系统的交互细节,提供简洁的高层接口
  2. 客户端只需调用外观类的方法,无需直接操作子系统
  3. 外观类负责协调多个子系统的调用顺序和交互方式
  4. 子系统之间可以相互交互,但客户端无需了解这些细节

外观模式与中介者模式的区别

  • 外观模式:关注简化客户端与子系统的交互,子系统之间可以直接通信
  • 中介者模式:关注子系统之间的通信,子系统通过中介者间接通信

外观模式的应用场景

  1. 当需要简化复杂子系统的使用时
  2. 当需要为一个复杂的子系统提供一个统一接口时
  3. 当需要隔离客户端与子系统,减少它们之间的依赖时
  4. 在分层架构中,可以为各层提供外观接口,简化层间交互

外观模式的优缺点

优点

  • 简化了客户端与子系统的交互,减少了客户端需要了解的类和方法
  • 降低了客户端与子系统之间的耦合度,提高了系统的可维护性
  • 有利于子系统的扩展和复用
  • 可以有多个外观类,分别针对不同场景提供接口

缺点

  • 外观类可能会变得过于庞大,承担过多责任,违背单一职责原则
  • 新增子系统功能可能需要修改外观类,违反开放-封闭原则
  • 可能隐藏了子系统的灵活性,限制了高级用户对系统的定制

外观模式在C++标准库中也有体现,例如std::iostream就是std::istreamstd::ostream等底层流类的外观,为复杂的输入输出操作提供了简单统一的接口。在大型框架中,外观模式也被广泛用于提供简洁的API入口。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐