软件开发经典设计模式:结构型-门面模式/组合模式/享元模式

门面模式:门面模式(Facade Pattern)是一种结构型设计模式,旨在为一个复杂子系统提供一个更简单、更统一的接口。门面模式通过引入一个高层接口,简化了子系统的使用和简化了交互过程,使得客户端只需与门面交互而不需要关心子系统内部的复杂实现。

核心思想

门面模式的核心思想是通过提供一个简化接口,将复杂系统的细节隐藏起来,提供一套更容易访问和使用的接口。这样做有助于减少客户端与子系统之间的耦合,并提供更高层次的操作。

组成部分

  1. 门面(Facade)

    • 提供一个客户可以操作的简单接口,封装子系统的复杂处理逻辑。
  2. 子系统类(Subsystem Classes)

    • 包含应用程序的内在功能,可以有多个不直接向客户端暴露的复杂的类。
  3. 客户端(Client)

    • 通过门面接口与子系统交互,而不需要直接与子系统的复杂结构和实现接触。

示例

下面是一个简单的 C++ 门面模式示例,展示了如何为一个音视频播放器提供简化接口:

#include <iostream>

// 子系统:音频管理
class AudioSystem {
public:
    void playSound() const {
        std::cout << "Playing sound..." << std::endl;
    }
};

// 子系统:视频管理
class VideoSystem {
public:
    void playVideo() const {
        std::cout << "Playing video..." << std::endl;
    }
};

// 子系统:字幕管理
class SubtitleSystem {
public:
    void showSubtitles() const {
        std::cout << "Displaying subtitles..." << std::endl;
    }
};

// 门面类
class MediaFacade {
public:
    MediaFacade()
        : audioSystem_(), videoSystem_(), subtitleSystem_() {}

    void playMedia() const {
        audioSystem_.playSound();
        videoSystem_.playVideo();
        subtitleSystem_.showSubtitles();
    }

private:
    AudioSystem audioSystem_;
    VideoSystem videoSystem_;
    SubtitleSystem subtitleSystem_;
};

// 客户端代码
int main() {
    MediaFacade mediaPlayer;
    mediaPlayer.playMedia();
    return 0;
}

特点和优点

  • 简化接口

    • 通过提供一个高层接口简化客户端与复杂子系统之间的交互。
  • 减少耦合

    • 客户端与子系统实现的依赖减弱,避免直接依赖子系统的具体实现。
  • 易于使用和维护

    • 更新子系统时,只需要修改门面类即可,客户端无须更改。

使用场景

  • 简化使用流程

    • 当你需要一个复杂子系统的简单接口时,使用门面模式让用户轻松完成任务。
  • 大量对象协作

    • 当系统由众多实现复杂的对象组成,并经常变动时,门面模式有助于提供合理稳定的接口。
  • 维护和扩展性考虑

    • 隐藏子系统的复杂性,封装变化,保持客户端代码的稳定性,使得系统更容易维护和扩展。

门面模式是简化复杂系统接口的有效工具,通过隐藏复杂实现,为系统提供简洁、统一的访问界面,尤其在复杂软件系统中尤为重要,可以大大提高使用体验以及系统的可维护性和扩展性。

 

组合模式:组合模式(Composite Pattern)是一种结构型设计模式,通过将对象组合成树状结构来表示“部分-整体”的层次。客户端可以统一地处理单个对象和对象的组合,从而实现对其内部多个对象的递归组合以及操作。在组合模式中,核心在于树形结构的处理,允许客户端在不同层级使用相同接口进行操作。

核心思想

组合模式的核心思想是让一个单一对象和一个组合对象拥有相同的接口,进而在系统中通过统一的方式管理和使用它们。这样,当你处理一组复杂的对象时,你无需针对每个对象区别对待,可以将它们作为一个整体来看待。

组成部分

  1. 组件(Component)

    • 定义所有类共有的接口,包括叶对象和组合对象。
  2. 叶子(Leaf)

    • 表示组合中的基本元素,它不会再包含子元素。
  3. 组合(Composite)

    • 区别于叶子,它是一个容器,可以包含并管理多个组件(它可以是叶子,也可以是其他组合)。
  4. 客户端(Client)

    • 通过组件接口来操作组合结构中的对象,包括单一对象和组合对象。

示例

下面是一个简单的 C++ 组合模式示例,模拟文件和文件夹的层次结构:

#include <iostream>
#include <vector>
#include <memory>
#include <string>

// 组件基类
class FileSystemComponent {
public:
    virtual ~FileSystemComponent() = default;
    virtual void show(int depth = 0) const = 0;
};

// 叶子类
class File : public FileSystemComponent {
public:
    explicit File(const std::string& name) : name_(name) {}

    void show(int depth = 0) const override {
        std::cout << std::string(depth, '-') << " File: " << name_ << std::endl;
    }

private:
    std::string name_;
};

// 组合类
class Directory : public FileSystemComponent {
public:
    explicit Directory(const std::string& name) : name_(name) {}

    void add(std::shared_ptr<FileSystemComponent> component) {
        components_.emplace_back(std::move(component));
    }

    void show(int depth = 0) const override {
        std::cout << std::string(depth, '-') << " Directory: " << name_ << std::endl;
        for (const auto& component : components_) {
            component->show(depth + 2);
        }
    }

private:
    std::string name_;
    std::vector<std::shared_ptr<FileSystemComponent>> components_;
};

// 客户端代码
int main() {
    auto root = std::make_shared<Directory>("root");
    auto subDir1 = std::make_shared<Directory>("subDir1");
    auto subDir2 = std::make_shared<Directory>("subDir2");

    root->add(std::make_shared<File>("file1.txt"));
    root->add(subDir1);
    subDir1->add(std::make_shared<File>("file2.txt"));
    subDir1->add(subDir2);
    subDir2->add(std::make_shared<File>("file3.txt"));

    root->show();

    return 0;
}

特点和优点

  • 透明性

    • 客户端可以一致地使用组合和叶子对象,无需关心它们的具体类型,对代码操作统一。
  • 灵活性

    • 可以很方便地增加新的组件类和组合类,符合开放/封闭原则。
  • 简洁的客户端代码

    • 客户端可以对组合结构中的所有对象进行统一处理,无需负责区分组合还是叶子。

使用场景

  • 树形结构表示

    • 当你希望表示对象的部分-整体层次结构,如文件系统、组织架构等。
  • 统一处理简单和复杂对象

    • 当希望客户端代码能够简化并可拓展时,可以使用组合模式。
  • 对象的一致性操作

    • 当需要对单个对象和组合对象进行相同的操作时,组合模式很适用。

组合模式是实现层次结构的一种有力工具,能够统一处理对象的个体和组合,尤其在需要递归处理对象结构、简化复杂对象操作的场合非常有用。通过这种灵活的方式,软件能够更轻松地管理复杂的数据结构。

 

享元模式:享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共用尽可能多的共享对象来减少内存使用和计算代价,特别是在同时存在大量细粒对象的场景下。享元模式通过共享众多对象的类似部分,实现对共享部分的复用,从而节省内存。

核心思想

享元模式通过将对象的状态分为内部状态(共享部分)和外部状态(非共享部分)来减少内存消耗。内部状态存储在享元对象中,并由多个上下文环境共享。外部状态由客户端在每次使用享元时传递。

组成部分

  1. 享元接口(Flyweight)

    • 为具体享元提供接口,通过传入外部状态进行操作。
  2. 具体享元(ConcreteFlyweight)

    • 实现享元接口,并存储享元对象的内部状态,从而可在多个上下文中共享。
  3. 非共享享元(UnsharedConcreteFlyweight)

    • 并非所有的享元对象都需要被共享,这些对象是不能被共享的,因为它们存储的是外部状态。
  4. 享元工厂(FlyweightFactory)

    • 创建并管理享元对象,确保正确地共享享元。用于检查一个对象是否已经创建,若是则返回现有对象,如果没有则创建一个新对象。
  5. 客户端(Client)

    • 维护对享元的引用,并负责将外部状态传递到享元中。

示例

以下是 C++ 中使用享元模式的一个简单示例,这个例子中模拟了一个字符处理的情景:

#include <iostream>
#include <unordered_map>
#include <memory>
#include <string>

// 享元接口
class Flyweight {
public:
    virtual void operation(const std::string& extrinsicState) const = 0;
    virtual ~Flyweight() = default;
};

// 具体享元
class ConcreteFlyweight : public Flyweight {
public:
    explicit ConcreteFlyweight(const std::string& intrinsicState)
        : intrinsicState_(intrinsicState) {}

    void operation(const std::string& extrinsicState) const override {
        std::cout << "ConcreteFlyweight: Intrinsic[" << intrinsicState_
                  << "] Extrinsic[" << extrinsicState << "]\n";
    }

private:
    std::string intrinsicState_;
};

// 享元工厂
class FlyweightFactory {
public:
    std::shared_ptr<Flyweight> getFlyweight(const std::string& key) {
        if (flyweights_.find(key) == flyweights_.end()) {
            flyweights_[key] = std::make_shared<ConcreteFlyweight>(key);
        }
        return flyweights_[key];
    }

private:
    std::unordered_map<std::string, std::shared_ptr<Flyweight>> flyweights_;
};

// 客户端代码
int main() {
    FlyweightFactory factory;

    std::shared_ptr<Flyweight> fw1 = factory.getFlyweight("A");
    std::shared_ptr<Flyweight> fw2 = factory.getFlyweight("B");
    std::shared_ptr<Flyweight> fw3 = factory.getFlyweight("A"); // Reuses existing instance

    fw1->operation("First Call");
    fw2->operation("Second Call");
    fw3->operation("Third Call");

    return 0;
}

特点和优点

  • 内存节约

    • 利用共享技术有效支持大量细粒度对象的共享。
  • 提高性能

    • 通过减少实际生成的对象数量来减少整体开销和所需的存储容量,从而提高系统性能。
  • 独立状态和行为

    • 将不变的部分(内部状态)和变化的部分(外部状态)分离开来,易于维护和修改。

使用场景

  • 大规模表示对象

    • 在需要大量细粒度的对象时,用共享的方式降低内存消耗。
  • 抽象属性

    • 区分内外部状态,当多数对象都能共享内在状态时。
  • 缓存和池化对象

    • 利用享元模式实现对象的缓存和重复利用,如池化连接、线程池、进程池等。

享元模式通过复用对象的共享属性来有效降低系统资源消耗,特别在性能和可伸缩性要求较高的应用程序中是一个极为有利的模式。通过合理运用享元模式,可以大大提高程序的效率,同时在需要对象管理的场合提供很好的解决方案。

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值