设计模式之享元模式

目录

1.概述

2.结构

3.实现

4.应用场景

5.总结


1.概述

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

2.结构

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

具体角色定义:

抽象享元(Flyweight):   定义了具体享元和非共享享元的接口,通常包含了设置外部状态的方法。

具体享元(Concrete Flyweight):  实现了抽象享元接口,包含了内部状态和外部状态。内部状态是可以被共享的,而外部状态则由客户端传递。上面的具体享元类ConcreteFlyweight是的内部状态是可以共享的,UnsharedConcreteFlyweight是指那些不需要共享的Flyweight子类,因为Flyweight接口共享成为可能,但是并不强制共享。

享元工厂(Flyweight Factory):  负责创建和管理享元对象,通常包含一个池(缓存)用于存储和复用已经创建的享元对象。工厂类内部维护一个享元对象的集合(通常是一个哈希表或字典),用于存储已经创建的享元对象。提供获取享元对象的方法,当请求某个享元对象时,工厂类首先检查集合中是否存在该对象,如果存在则直接返回,否则创建新的享元对象并添加到集合中。

客户端(Client) 使用享元工厂获取享元对象,并通过设置外部状态来操作享元对象。客户端通常不需要关心享元对象的具体实现。

3.实现

简单实现代码如下:

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

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

  • 17
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
享元设计模式(Flyweight Design Pattern)是一种用于优化大量对象创建和使用的设计模式。在Android开发中,使用享元模式可以有效地减少内存消耗和提高性能。 在享元模式中,对象被分为两种状态:内部状态和外部状态。内部状态是不变的,可以被多个对象共享,而外部状态是可变的,每个对象都有自己的外部状态。 在Android中,典型的例子是使用Bitmap对象来显示图片。当需要显示多个相同的图片时,可以使用享元模式来共享已加载的Bitmap对象,而不是每次都创建新的Bitmap对象。 以下是一个简单的示例代码: ```java public class BitmapFactory { private Map<String, Bitmap> bitmapCache = new HashMap<>(); public Bitmap getBitmap(String path) { Bitmap bitmap = bitmapCache.get(path); if (bitmap == null) { // 如果缓存中没有该Bitmap对象,则创建新的Bitmap对象 bitmap = BitmapFactory.decodeFile(path); bitmapCache.put(path, bitmap); } return bitmap; } } ``` 在上面的示例中,`BitmapFactory` 类使用一个 `bitmapCache` Map 来缓存已加载的 Bitmap 对象。当需要获取 Bitmap 对象时,首先从缓存中查找,如果找到则返回缓存的对象,否则创建新的 Bitmap 对象并存入缓存。 通过使用享元模式,可以避免重复创建相同的 Bitmap 对象,从而减少内存消耗。这在需要频繁加载和显示大量图片的应用中非常有用。 需要注意的是,享元模式适用于有大量相似对象的情况,并且需要权衡共享对象和创建对象的开销。在某些情况下,过度使用享元模式可能会导致代码复杂化,降低可读性和可维护性。因此,在使用享元模式时应根据实际情况进行评估和折衷。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值