设计模式-09 - 享元模式 flyweight pattern

设计模式-09 - 享元模式  flyweight pattern

1.定义

享元模式是一种设计模式,它使用共享对象来减少内存使用和提高性能。它通过存储共享的对象实例池来实现,这些实例可以被多个客户端同时使用。

享元模式定义了一个接口,使客户端可以访问共享的轻量级对象。享元可以根据其内部状态进行细分,客户端只需要提供它需要的状态即可。享元对象被存储在共享池中,如果客户端请求一个已经存在的享元,则会返回该享元,否则会创建一个新的享元并将其添加到池中。



                +--------------------+
                | Flyweight Factory  |
                +--------------------+
                          |
                 +--------------------+
                 | Concrete Flyweight |
                 +--------------------+
                 |                    |
                 |                    |
                 |                    |
                 |                    |
                 +--------------------+
							  |
			  +--------------------------+
			  | Context (with Flyweight) |
			  +--------------------------+


说明:

  • Flyweight Factory:创建和管理享元对象。
  • Concrete Flyweight:实现享元接口的具体对象。享元对象是轻量级的、不可变的,并且具有大量重复实例。
  • Context:使用享元对象,并为其提供外部状态。
2.内涵

享元模式通常用于以下场景:

  • 当需要大量相同或相似对象时,例如在图形应用程序中表示图像或文本。
  • 当对象状态存储在外部数据结构中时,例如在数据库或缓存中。
  • 当对象创建或销毁成本很高时。

一个常见的享元模式示例是字符集中的字符对象。每个字符都可以表示为享元对象,其状态是字符的外观。当需要显示文本时,应用程序可以请求字符享元,而不需要为每个字符创建一个单独的对象。

享元模式与其他设计模式有一些相似之处:

  • 单例模式:享元模式与单例模式类似,因为它创建了一个共享对象,但享元模式允许创建多个共享对象。
  • 工厂方法模式:享元模式可以使用工厂方法模式来创建共享对象。
  • 策略模式:享元模式可以使用策略模式来存储对象的内部状态。

3.使用示例
#include <iostream>
#include <unordered_map>

// Flyweight class
class Character {
public:
    Character(char intrinsicState) : m_intrinsicState(intrinsicState) {}

    void draw(int extrinsicState) {
        std::cout << "Drawing character '" << m_intrinsicState << "' at position " << extrinsicState << std::endl;
    }

private:
    char m_intrinsicState;
};

// Flyweight factory
class CharacterFactory {
public:
    Character* getCharacter(char key) {
        if (m_characters.find(key) == m_characters.end()) {
            m_characters[key] = new Character(key);
        }
        return m_characters[key];
    }

private:
    std::unordered_map<char, Character*> m_characters;
};

int main() {
    CharacterFactory characterFactory;

    // Extrinsic state
    int position = 0;

    // Drawing characters 'A', 'B', 'C' at different positions
    characterFactory.getCharacter('A')->draw(position++);
    characterFactory.getCharacter('B')->draw(position++);
    characterFactory.getCharacter('C')->draw(position++);

    return 0;
}

4.注意事项


在使用享元模式时,需要注意以下事项:

  • 确定可共享的对象:并非所有对象都适合共享。只有当对象是轻量级的、不可变的并且具有大量重复实例时,才应考虑使用享元模式。
  • 管理对象状态:享元对象必须是不可变的,这意味着它们的状态一旦创建就不能被改变。如果对象需要可变状态,则可能需要使用其他设计模式,例如策略模式。
  • 处理并发性:如果多个客户端同时访问享元对象,则需要考虑并发性问题。可以使用同步机制来确保对象状态的一致性。
  • 避免过度共享:虽然共享对象可以减少内存使用,但过度共享可能会导致性能下降。只应共享真正需要的对象。
  • 考虑代码复杂性:享元模式可以引入一些代码复杂性,因为它需要管理共享对象池。在使用享元模式之前,应权衡收益和成本。
  • 其他注意事项:
  • 对象识别:享元对象需要一种方法来被客户端识别。这通常是通过使用唯一标识符或其他属性来实现的。
  • 外部状态:享元对象可以存储外部状态,但该状态不应修改享元对象本身。
  • 性能优化:为了优化享元模式的性能,应使用对象池来管理共享对象。对象池可以减少创建和销毁对象的开销。
  • 可测试性:享元模式的实现应可测试,以验证共享对象的正确性。可以使用单元测试来验证对象池的功能和共享对象的不可变性。
5.最佳实践


 
享元模式(Flyweight Pattern)最佳实践

1. 仅对可共享对象使用享元:

享元对象应是轻量级的、不可变的,并且具有大量重复实例。
2. 使用对象池管理共享对象:

对象池可以减少创建和销毁对象的开销,从而提高性能。
3. 确保对象不可变性:

享元对象的状态一旦创建就不能被改变。
4. 考虑并发性:

如果多个客户端同时访问享元对象,则需要考虑并发性问题。可以使用同步机制来确保对象状态的一致性。
5. 避免过度共享:

只应共享真正需要的对象。过度共享可能会导致性能下降。
6. 使用唯一标识符识别对象:

享元对象需要一种方法来被客户端识别。这通常是通过使用唯一标识符或其他属性来实现的。
7. 将外部状态存储在其他对象中:

享元对象可以存储外部状态,但该状态不应修改享元对象本身。
8. 使用单元测试验证共享对象的正确性:

单元测试可以验证对象池的功能和共享对象的不可变性。


6.总结


在使用享元模式时,应遵循设计原则,例如单一职责原则、开放/封闭原则和里氏替换原则。
通过遵循这些最佳实践,可以有效地使用享元模式来提高应用程序的性能和可维护性。

相关推荐

  1. 设计模式

    2024-05-12 07:28:04       34 阅读
  2. 设计模式-09 - 模式 flyweight pattern

    2024-05-12 07:28:04       9 阅读
  3. 设计模式-模式

    2024-05-12 07:28:04       32 阅读
  4. 设计模式模式

    2024-05-12 07:28:04       16 阅读
  5. 设计模式模式

    2024-05-12 07:28:04       14 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-12 07:28:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-12 07:28:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-12 07:28:04       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-12 07:28:04       20 阅读

热门阅读

  1. Linux权限(二)

    2024-05-12 07:28:04       11 阅读
  2. 数据结构之队列

    2024-05-12 07:28:04       9 阅读
  3. DBSCAN聚类算法

    2024-05-12 07:28:04       12 阅读
  4. WEB前端复习——HTML

    2024-05-12 07:28:04       11 阅读
  5. UML 方法

    2024-05-12 07:28:04       14 阅读
  6. C语言-STM32:初始定时器(通用定时器)

    2024-05-12 07:28:04       9 阅读
  7. Lua 协程池

    2024-05-12 07:28:04       12 阅读
  8. EureKa详细讲解通俗易懂

    2024-05-12 07:28:04       10 阅读
  9. flask+layui显示监控视频

    2024-05-12 07:28:04       12 阅读
  10. 代码绘梦:Processing艺术编程入门

    2024-05-12 07:28:04       8 阅读
  11. 大数据调度 Apache Airflow 安装部署

    2024-05-12 07:28:04       14 阅读