设计模式之享元模式

目录

1.概述

2.结构

3.实现

4.应用场景

5.总结


1.概述

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,通过使用共享对象来支持大量的细粒度对象,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。在享元模式中,有些对象可以被多个客户端共享,以减少创建对象的数量。享元模式的核心在于享元工厂类,它负责创建和管理享元对象,并提供对外访问的接口。

2.结构

享元模式的结构图如下所示:

具体角色定义:

抽象享元(Flyweight): 定义了具体享元和非共享享元的接口,通常包含了设置外部状态的方法。
具体享元(Concrete Flyweight) :实现了抽象享元接口,包含了内部状态和外部状态。内部状态是可以被共享的,而外部状态则由客户端传递。上面的具体享元类ConcreteFlyweight是的内部状态是可以共享的,UnsharedConcreteFlyweight是指那些不需要共享的Flyweight子类,因为Flyweight接口共享成为可能,但是并不强制共享。
享元工厂(Flyweight Factory) :负责创建和管理享元对象,通常包含一个池(缓存)用于存储和复用已经创建的享元对象。工厂类内部维护一个享元对象的集合(通常是一个哈希表或字典),用于存储已经创建的享元对象。提供获取享元对象的方法,当请求某个享元对象时,工厂类首先检查集合中是否存在该对象,如果存在则直接返回,否则创建新的享元对象并添加到集合中。
客户端(Client) : 使用享元工厂获取享元对象,并通过设置外部状态来操作享元对象。客户端通常不需要关心享元对象的具体实现。

3.实现

简单实现代码如下:

cpp 复制代码
#include <iostream>  
#include <unordered_map>  
#include <string>  
  
// 享元接口  
class Flyweight {  
public:  
    virtual ~Flyweight() {}  
    virtual void operation(const std::string& extrinsicState) = 0;  
};  
  
// 具体的享元类  
class ConcreteFlyweight : public Flyweight {  
private:  
    std::string intrinsicState; // 内部状态  
  
public:  
    ConcreteFlyweight(const std::string& state) : intrinsicState(state) {}  
  
    void operation(const std::string& extrinsicState) override {  
        std::cout << "Intrinsic: " << intrinsicState << ", Extrinsic: " << extrinsicState << std::endl;  
    }  
};  
  
// 享元工厂类  
class FlyweightFactory {  
public:
    ~FlyweightFactory(){
        for (auto& it : m_flyweights){
            delete it.second;
        }
        m_flyweights.clear();
    }
  
public:  
    Flyweight* getFlyweight(const std::string& key) {  
        if (m_flyweights.find(key) == m_flyweights.end()) {  
            m_flyweights[key] = new ConcreteFlyweight(key);  
        }  
        return m_flyweights[key];  
    }  
private:  
    std::unordered_map<std::string, Flyweight*> m_flyweights;  
};  
  
int main() {  
    FlyweightFactory factory;  
    Flyweight* fw1 = factory.getFlyweight("A");  
    Flyweight* fw2 = factory.getFlyweight("B");  
    Flyweight* fw3 = factory.getFlyweight("A"); // 复用 fw1  
  
    fw1->operation("X");  
    fw2->operation("Y");  
    fw3->operation("Z"); // 使用与 fw1 相同的对象   
  
    return 0;  
}

在这个示例中,Flyweight 是一个接口,定义了享元对象应该具有的操作。ConcreteFlyweight 是具体的享元类,它包含内部状态(intrinsicState)并实现了操作。FlyweightFactory 是一个工厂类,它负责创建和管理享元对象。通过使用 FlyweightFactory,我们可以确保对于相同的内部状态,只创建一个 ConcreteFlyweight 对象,并在后续请求时复用它。

4.应用场景

在 C++ 中,享元模式的应用场景主要出现在需要处理大量相似或重复对象,且这些对象的内存占用较大时。通过共享这些对象的状态,享元模式能够显著减少内存消耗,并提高系统的性能。

具体来说,以下是一些 C++ 中享元模式的应用场景:

图形界面开发:在图形用户界面中,可能需要大量的按钮、图标或其他 UI 元素。这些元素通常具有相似的外观和行为,但数量众多。通过应用享元模式,可以共享这些元素的内部状态,减少内存占用。

字符串处理:在 C++ 中,字符串的创建和销毁是一个常见的性能瓶颈。使用享元模式,可以设计一个字符串缓存池,对于相同的字符串,只在缓存池中保留一份实例,多次使用时直接引用该实例,避免了重复的创建和销毁操作。

数据库连接池:在数据库应用中,频繁地创建和关闭数据库连接会消耗大量的系统资源。通过使用享元模式实现连接池,可以复用已建立的数据库连接,提高系统性能和稳定性。

游戏开发:在游戏中,经常需要创建大量的相似对象,如棋子、怪物、子弹等。这些对象可能具有相同的属性或行为,但由于数量众多,如果每个对象都单独创建,将会占用大量的内存。使用享元模式,可以将这些对象的共享部分提取出来,只保留一份实例,从而大大减少内存消耗。

总的来说,享元模式在 C++ 中的应用场景主要是那些需要处理大量相似或重复对象,且内存消耗成为性能瓶颈的情况。通过共享对象的状态,享元模式能够优化内存使用,提高系统的整体性能。

5.总结

优点:

(1) 减少内存占用:享元模式通过共享相同或相似的对象,避免了大量相同对象的重复创建,从而显著降低了系统的内存占用。

(2) 提高系统性能:由于减少了对象的创建和销毁,享元模式可以提高系统的运行效率。特别是在需要大量创建对象的场景中,这种性能提升尤为明显。

(3) 支持高并发:在高并发的系统中,对象的创建和销毁可能会成为性能瓶颈。享元模式通过共享对象实例,减少了对象的创建和销毁,从而支持更高的并发量。

缺点:

(1) 提高了系统的复杂度:享元模式需要分离出对象的内部状态和外部状态,这增加了系统的复杂性和编程难度。同时,为了管理这些状态,可能需要引入额外的数据结构(如哈希表等),进一步增加了系统的复杂性。

(2) 可能导致系统混乱:如果外部状态具有固有化的性质,不应该随着内部状态的变化而变化,但在实际使用中违反了这一原则,就可能导致系统混乱。因此,在使用享元模式时,需要特别注意外部状态的管理。

(3) 不适合所有场景:虽然享元模式在某些场景下可以提高系统性能和减少内存占用,但并不是所有场景都适合使用享元模式。例如,当对象的状态经常变化或者对象之间的差别较大时,使用享元模式可能并不合适。

综上所述,享元模式在减少内存占用和提高系统性能方面具有明显的优势,但同时也存在提高系统复杂度和可能导致系统混乱的缺点。因此,在决定是否使用享元模式时,需要根据具体的应用场景和需求进行权衡。

相关推荐
JSU_曾是此间年少20 分钟前
数据结构——线性表与链表
数据结构·c++·算法
此生只爱蛋1 小时前
【手撕排序2】快速排序
c语言·c++·算法·排序算法
何曾参静谧2 小时前
「C/C++」C/C++ 指针篇 之 指针运算
c语言·开发语言·c++
暗黑起源喵2 小时前
设计模式-工厂设计模式
java·开发语言·设计模式
lulu_gh_yu2 小时前
数据结构之排序补充
c语言·开发语言·数据结构·c++·学习·算法·排序算法
ULTRA??3 小时前
C加加中的结构化绑定(解包,折叠展开)
开发语言·c++
凌云行者4 小时前
OpenGL入门005——使用Shader类管理着色器
c++·cmake·opengl
凌云行者4 小时前
OpenGL入门006——着色器在纹理混合中的应用
c++·cmake·opengl
~yY…s<#>4 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
可均可可5 小时前
C++之OpenCV入门到提高004:Mat 对象的使用
c++·opencv·mat·imread·imwrite