实战设计模式之外观模式

概述

与前一篇介绍的组合模式相同,外观模式也是一种结构型设计模式。通过引入一个外观类,将多个系统的接口整合成一个高层次的接口,使得客户端可以更容易地使用这些系统。这个模式的主要目的是:降低系统的耦合度,简化客户端与子系统之间的交互。

汽车驾驶是现实生活中运用外观模式的一个典型例子:当我们驾驶一辆汽车时,实际上是在与多个复杂的子系统进行互动(比如:发动机系统、刹车系统、转向系统、空调系统等);然而,驾驶员并不需要了解这些系统的内部工作原理,只需要操作方向盘、油门踏板、刹车踏板和一些简单的按钮即可。

基本原理

外观模式的核心思想是:简化接口和解耦。对于复杂的子系统,外观模式提供了一个更简单、更高层次的接口,使得客户端无需了解每个子系统的内部细节。同时,它还减少了客户端对子系统的直接依赖,从而提高了系统的灵活性和可维护性。即使子系统内部发生变化,只要外观类提供的接口不变,客户端代码就不需要修改。外观模式主要由以下三个核心组件构成。

1、外观类。它为子系统提供了一个简化的接口,封装了对多个子系统的调用逻辑。外观类可能会持有对子系统对象的引用,以便在需要时调用它们的方法。

2、子系统类。它实现了系统的具体功能,但其接口可能是复杂或低级的。每个子系统都可以独立工作,也可以与其他子系统协作。子系统类通常不需要知道其他子系统的存在,以保持较低的耦合度。

3、客户端。通过外观类提供的接口与子系统交互,而不必直接调用子系统的方法。客户端只需要关注外观类提供的高层接口,而不需要理解每个子系统的细节。

基于上面的核心组件,外观模式的实现主要有以下四个步骤。

1、识别复杂的子系统。分析现有系统,找出那些具有复杂接口或相互依赖的模块,这些模块将成为外观模式中的子系统。比如:在汽车驾驶中,发动机系统、刹车系统、转向系统、空调系统等都是独立的子系统。

2、设计外观类。创建一个外观类,它应该包含所有必要的方法来简化客户端与子系统的交互。外观类的方法应当易于理解和使用,并且能够协调各个子系统的操作。

3、集成子系统。在外观类的内部,实现对各个子系统的调用逻辑,以确保外观类能够正确地协调不同子系统之间的操作。

4、编写客户端代码。客户端代码不应直接依赖于具体的子系统类,而应使用外观类提供的接口与子系统进行交互。

实战解析

在下面的实战代码中,我们使用外观模式模拟了汽车驾驶的实现。

首先,我们定义了四个子系统类。CEngineSystem负责管理发动机的启动和停止,CBrakeSystem提供应用和释放刹车的功能,CSteeringSystem实现左转、右转和校正方向的操作,CAirConditioning控制空调的开关及温度设置。

接下来,我们实现了外观类CCarFacade。其构造函数中初始化了所有子系统的实例,并在析构函数中确保这些资源被正确清理。CCarFacade提供了一系列简化的方法,比如:StartCar、StopCar、Accelerate等,其内部会协调各个子系统的具体操作。可以看到,外观类封装了复杂的子系统逻辑,为客户端提供了相对简化的接口。

最后,在main函数中,我们创建了一个CCarFacade类的实例pCar,代表汽车的外观。通过调用pCar的方法,我们模拟了一连串驾驶行为,比如:启动汽车、加速、转弯、刹车等。

cpp 复制代码
#include <iostream>
using namespace std;

// 子系统类:发动机系统
class CEngineSystem
{
public:
    void Start() { cout << "Engine started\n"; }
    void Stop() { cout << "Engine stopped\n"; }
};

// 子系统类:刹车系统
class CBrakeSystem
{
public:
    void ApplyBrakes() { cout << "Brakes applied\n"; }
    void ReleaseBrakes() { cout << "Brakes released\n"; }
};

// 子系统类:转向系统
class CSteeringSystem
{
public:
    void TurnLeft() { cout << "Turn left\n"; }
    void TurnRight() { cout << "Turn right\n"; }
    void Straighten() { cout << "Straighten the wheel\n"; }
};

// 子系统类:空调系统
class CAirConditioning
{
public:
    void TurnOn() { cout << "Air conditioning turned on\n"; }
    void TurnOff() { cout << "Air conditioning turned off\n"; }
    void SetTemperature(int temperature)
    {
        cout << "Set temperature to " << temperature << " degrees\n";
    }
};

// 外观类:汽车外观
class CCarFacade
{
public:
    CCarFacade() : m_pEngine(new CEngineSystem()),
        m_pBrakeSystem(new CBrakeSystem()),
        m_pSteeringSystem(new CSteeringSystem()),
        m_pAirConditioning(new CAirConditioning()) {}

    ~CCarFacade()
    {
        delete m_pEngine;
        delete m_pBrakeSystem;
        delete m_pSteeringSystem;
        delete m_pAirConditioning;
    }

    void StartCar()
    {
        cout << "Starting the car...\n";
        m_pEngine->Start();
        m_pAirConditioning->TurnOn();
        m_pAirConditioning->SetTemperature(23);
    }

    void StopCar()
    {
        cout << "Stopping the car...\n";
        m_pAirConditioning->TurnOff();
        m_pEngine->Stop();
    }

    void Accelerate()
    {
        cout << "Accelerating...\n";
    }

    void Brake()
    {
        cout << "Applying brakes...\n";
        m_pBrakeSystem->ApplyBrakes();
    }

    void ReleaseBrake()
    {
        cout << "Releasing brakes...\n";
        m_pBrakeSystem->ReleaseBrakes();
    }

    void TurnLeft()
    {
        cout << "Turning left...\n";
        m_pSteeringSystem->TurnLeft();
    }

    void TurnRight()
    {
        cout << "Turning right...\n";
        m_pSteeringSystem->TurnRight();
    }

    void StraightenWheel()
    {
        cout << "Straightening the wheel...\n";
        m_pSteeringSystem->Straighten();
    }

private:
    CEngineSystem* m_pEngine;
    CBrakeSystem* m_pBrakeSystem;
    CSteeringSystem* m_pSteeringSystem;
    CAirConditioning* m_pAirConditioning;
};

int main()
{
    // 创建汽车外观对象
    CCarFacade* pCar = new CCarFacade();

    // 使用外观对象简化操作
    pCar->StartCar();
    pCar->Accelerate();
    pCar->TurnRight();
    pCar->TurnLeft();
    pCar->Brake();
    pCar->ReleaseBrake();
    pCar->StraightenWheel();
    pCar->StopCar();

    // 清理资源
    delete pCar;
    return 0;
}

总结

外观模式通过提供一个简化的接口来隐藏复杂的子系统,使得客户端代码可以更轻松地使用这些系统。这减少了客户端需要了解的细节,降低了学习曲线。如果子系统发生变化,比如:增加新功能或重构现有功能,只需更新外观类即可,无需修改所有依赖于该子系统的客户端代码。另外,在大型项目中,可以通过多个外观类来分层管理不同级别的子系统,使得系统的层次更加清晰,易于理解和维护。

但对于小型或简单的应用程序,引入外观类可能会显得多余,增加了不必要的复杂性和代码量。尤其是在系统本身已经足够直观的情况下,添加外观类可能不会带来显著的好处。虽然外观模式简化了接口,但它也可能隐藏了一些高级功能。如果客户端需要直接访问子系统的特定特性,则必须绕过外观类,这会破坏外观模式带来的透明性和简化效果。

相关推荐
专注API从业者3 小时前
分布式电商系统中的API网关架构设计
大数据·数据仓库·分布式·架构
付聪12105 小时前
装饰器模式
设计模式
扣丁梦想家5 小时前
设计模式教程:外观模式(Facade Pattern)
设计模式·外观模式
強云5 小时前
23种设计模式 - 装饰器模式
c++·设计模式·装饰器模式
強云5 小时前
23种设计模式 - 外观模式
设计模式·外观模式
uhakadotcom5 小时前
Google DeepMind最近发布了SigLIP 2
人工智能·算法·架构
鄃鳕6 小时前
单例模式【C++设计模式】
c++·单例模式·设计模式
HsuYang8 小时前
Vite源码学习(十二)——热更新(下)
前端·javascript·架构
BlueBirdssh8 小时前
ARM SOC 架构系统M系、R系、A系
arm开发·架构
扣丁梦想家9 小时前
设计模式教程:命令模式(Command Pattern)
设计模式·命令模式