实战设计模式之外观模式

概述

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

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

基本原理

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

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;
}

总结

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

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

相关推荐
安思派Anspire20 分钟前
LangGraph + MCP + Ollama:构建强大代理 AI 的关键(一)
前端·深度学习·架构
radient1 小时前
Golang-GMP 万字洗髓经
后端·架构
Code季风1 小时前
Gin Web 层集成 Viper 配置文件和 Zap 日志文件指南(下)
前端·微服务·架构·go·gin
鹏程十八少1 小时前
9.Android 设计模式 模板方法 在项目中的实战
架构
Gavynlee3 小时前
plantuml用法总结
设计模式
DKPT3 小时前
Java享元模式实现方式与应用场景分析
java·笔记·学习·设计模式·享元模式
缘来是庄3 小时前
设计模式之迭代器模式
java·设计模式·迭代器模式
程序员JerrySUN4 小时前
RK3588 Android SDK 实战全解析 —— 架构、原理与开发关键点
android·架构
No Silver Bullet4 小时前
软件工程功能点估算基础
软件工程·功能点估算
No Silver Bullet4 小时前
软件工程功能点估算法常用术语介绍
java·开发语言·软件工程