设计模式——外观模式

文章目录

  • [1. 定义](#1. 定义)
  • [2. 结构组成](#2. 结构组成)
  • [3. 外观模式结构](#3. 外观模式结构)
  • [4. 示例代码](#4. 示例代码)
  • [5. 模式优势](#5. 模式优势)
  • [6. 应用场景](#6. 应用场景)

1. 定义

外观模式就像是酒店的前台。酒店内部有很多部门,如客房部、餐饮部、后勤部等,这些部门就像是软件系统中的子系统。而前台就像是外观模式中的 "外观(Facade)" 类,客人(客户端)不需要知道酒店内部各个部门是如何运作的,只需要通过前台就能解决很多问题,比如订房、订餐等。

简单来说,外观模式提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。

2. 结构组成

  • 外观(Facade)类:
    • 这是外观模式的核心。它知道哪些子系统负责处理请求,并将客户端的请求代理给适当的子系统对象。在酒店的例子中,前台就是这个 Facade 类,它知道客人的需求该转交给哪个部门处理。
  • 子系统(Subsystem)类:
    • 这些是实现具体功能的类。在酒店里,客房部、餐饮部等就是子系统类。它们各自有自己的业务逻辑,但是都被外观类所调用。例如,客房部负责房间的分配和管理,餐饮部负责食物的制作和供应。
  • 客户端(Client)类:
    • 客户端是使用外观类来访问子系统的类。在酒店场景中,客人就是客户端,他们通过前台(外观类)来享受酒店的各种服务,而不需要直接和各个部门(子系统类)打交道。
  • 创建附加外观(Additional Facade)类:
    • 创建附加外观类可以避免多种不相关的功能污染单一外观,使其变成又一个复杂结构。客户端和其他外观都可使用附加外观。在酒店场景中,可能存在不同类型的服务套餐,每种套餐对应一个附加外观。例如,商务套餐对应的附加外观可以集成客房服务、会议室预订和商务餐饮等特定服务,而旅游套餐对应的附加外观可以集成客房服务、旅游景点票务和特色餐饮等服务。这样,不同需求的客人(客户端)可以通过不同的附加外观(Additional Facade)来获取更有针对性的服务,而无需在单一外观(Facade)中混杂所有功能。

3. 外观模式结构

  • 外观 (Facade) 提供了一种访问特定子系统功能的便捷方式, 其了解如何重定向客户端请求, 知晓如何操作一切活动部件。

  • 创建附加外观 (Additional Facade) 类可以避免多种不相关的功能污染单一外观, 使其变成又一个复杂结构。 客户端和其他外观都可使用附加外观。

  • 复杂子系统 (Complex Subsystem) 由数十个不同对象构成。 如果要用这些对象完成有意义的工作, 你必须深入了解子系统的实现细节, 比如按照正确顺序初始化对象和为其提供正确格式的数据。

  • 子系统类不会意识到外观的存在, 它们在系统内运作并且相互之间可直接进行交互。

  • 客户端 (Client) 使用外观代替对子系统对象的直接调用。

4. 示例代码

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

using namespace std;

class Subsystem1{
public:
    Subsystem1(){cout << "Construct Subsystem1" <<endl;}
    ~Subsystem1(){cout << "Destruct Subsystem1" <<endl;}

    string Operation1() const {
        return "Subsystem1: Ready!\n";
    }

    string OperationN() const {
        return "Subsystem1: Go!\n";
    }
    
    string optionalOperation() const {
        return "Subsystem1: optionalOperation";
    }
};

class Subsystem2{
public:
    Subsystem2(){cout << "Construct Subsystem2" <<endl;}
    ~Subsystem2(){cout << "Destruct Subsystem2" <<endl;}

    string Operation1() const {
        return "Subsystem2: Get ready!\n";
    }

    string OperationZ() const {
        return "Subsystem2: Fire!\n";
    }
};

class AdditionalFacade{
private:
    shared_ptr<Subsystem1> subsystem1_;
public:
    AdditionalFacade(shared_ptr<Subsystem1> subsystem1):subsystem1_(subsystem1) {
        cout << "Construct AdditionalFacade" <<endl;}
    ~AdditionalFacade(){cout << "Destruct AdditionalFacade" <<endl;}
    
    string anotherOperation() const{
        string result;
        result += subsystem1_->optionalOperation();
        return result;
    }
};

class Facade{
private:
    shared_ptr<Subsystem1> subsystem1_;
    unique_ptr<Subsystem2> subsystem2_;
    vector<shared_ptr<AdditionalFacade>> additionalF;
public:
    Facade(shared_ptr<Subsystem1> subsystem1 = nullptr,
            unique_ptr<Subsystem2> subsystem2 = nullptr){
        
        if(subsystem1)
            subsystem1_ = subsystem1;
        else
            subsystem1_ = make_shared<Subsystem1>();
        
        if(subsystem2)
            subsystem2_ = move(subsystem2);
        else 
            subsystem2_ = make_unique<Subsystem2>();
            
        cout << "Construct Facade" <<endl;
    }
    ~Facade(){cout << "Destruct Facade" <<endl;}

    string Operation() const{
        string result = "Facade initializes subsystems:\n";
        result += this->subsystem1_->Operation1();
        result += this->subsystem2_->Operation1();
        result += "Facade orders subsystems to perform the action:\n";
        result += this->subsystem1_->OperationN();
        result += this->subsystem2_->OperationZ();
        return result;
    }
    
    string optionalAdditionalFacade()const{
        string result;
        for(auto & AF : additionalF){
            result += AF->anotherOperation();
        }
        
        return result;
    }
    
    void addAdditionalFacade(shared_ptr<AdditionalFacade> additionalfacade){
        additionalF.push_back(additionalfacade);
    }
    
};

void ClientCode(shared_ptr<Facade> facade){
    cout<< facade->Operation() <<endl;
    cout<< facade->optionalAdditionalFacade() <<endl;
}

int main()
{
    shared_ptr<Subsystem1> subsystem1 = make_shared<Subsystem1>();
    unique_ptr<Subsystem2> subsystem2 = make_unique<Subsystem2>();
    shared_ptr<Facade> facade = make_shared<Facade>(subsystem1, move(subsystem2));
    ClientCode(facade);
    
    shared_ptr<AdditionalFacade> additionalFacade = make_shared<AdditionalFacade>(subsystem1);
    facade->addAdditionalFacade(additionalFacade);
    ClientCode(facade);
    
    return 0;
}

5. 模式优势

  • 简化了接口
    • 客户端不需要了解子系统内部的复杂结构和操作。就像客人不需要知道酒店内部的运作流程,只通过前台就能解决问题,降低了客户端的使用难度。
  • 减少系统的相互依赖
    • 子系统的变化不会直接影响到客户端。例如,酒店的客房部内部管理系统升级,只要前台(外观类)的接口不变,客人(客户端)就不会受到影响。
  • 提高了灵活性
    • 可以很方便地在外观类中添加或删除对子系统的调用。比如酒店增加了一个健身房服务,只需要在前台(外观类)增加对健身房部门的调用接口即可,而不需要改变客人(客户端)的使用方式。
  • 便于功能扩展和定制
    • 通过创建附加外观,可以针对不同的业务需求进行功能扩展和定制。例如,酒店可以根据不同的客户群体(商务客人、旅游客人等)创建不同的附加外观,提供个性化的服务套餐,而不会影响基本外观和子系统的原有结构。

6. 应用场景

  • 分层架构
    • 在多层架构的软件系统中,外观模式可以用来为底层的复杂业务逻辑提供一个简单的高层接口。例如,在一个电商系统中,订单处理、库存管理、物流配送等底层业务逻辑复杂,通过外观模式可以为前端应用提供一个简单的下单、查询订单状态等接口。
  • 第三方库集成
    • 当软件系统需要集成多个第三方库时,外观模式可以用来封装这些库的接口,使其使用更加方便。比如一个应用程序需要集成多个地图库、支付库等,通过外观模式可以将这些库的复杂接口封装起来,为应用程序提供统一的调用接口。
  • 系统启动和关闭
    • 对于有多个子系统需要按特定顺序启动和关闭的情况,外观模式可以提供一个简单的接口来处理。例如,一个大型服务器系统有数据库、缓存、应用服务器等多个子系统,通过外观模式可以编写一个统一的启动和关闭程序来管理这些子系统的顺序操作。
  • 功能套餐定制
    • 在需要为用户提供不同功能套餐的场景中,创建附加外观非常适用。例如,软件即服务(SaaS)平台可以为不同类型的用户(如企业用户、个人用户等)创建不同的附加外观,每个附加外观可以集成平台中的部分子系统功能,形成不同的功能套餐,满足不同用户的需求。
相关推荐
艾斯特_1 小时前
前端设计模式介绍及案例(单例模式、代理模式、工厂模式、装饰者模式、观察者模式)
前端·javascript·观察者模式·单例模式·设计模式
weixin_438335401 小时前
设计模式之策略模式
设计模式·策略模式
Shinka-深深2 小时前
《图解设计模式》笔记(七)简单化
笔记·设计模式
Shinka-深深2 小时前
《图解设计模式》笔记(六)访问数据结构
笔记·设计模式
吴天德少侠11 小时前
设计模式中的关联和依赖区别
java·开发语言·设计模式
Zhen (Evan) Wang11 小时前
23种设计模式的定义和应用场景-02-结构型模式-C#代码
设计模式
大明湖的狗凯.17 小时前
Java设计模式——责任链模式与策略模式
java·设计模式·责任链模式
_DCG_18 小时前
c++设计模式之策略模式
c++·设计模式·策略模式
FLZJ_KL1 天前
【设计模式】【行为型模式】职责链模式(Chain of Responsibility)
设计模式·责任链模式·职责链模式
jf加菲猫1 天前
12 代理(Proxy)模式
c++·设计模式