Flyweight模式

意图:

运用共享技术有效的支持大量细粒度对象


适用性:

1一个应用程序使用了大量的对象

2由于使用大量的对象造成很大的开销

3对象的大多数状态都可变为外部状态

4如果删除对象的外部状态,可以用相对较少的共享对象,取代很多组对象

5应用程序不依赖于对象标识


效果:

使用FLYWEIGHT模式后,传输查找和计算外部状态都会产生开销,然而空间上的节省抵消了这些开销。

1因为共享,实例总数减少的数目

2对象内部状态的平均数目

3外部状态存储





1、抽象享元(Flyweight)角色:此角色是所有的具体享元类的基类,为这些类规定出需要实现的公共接口,通过这个接口Flyweight可以接受并作用于外部状态。
2、具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定的接口。如果有内蕴状态(Intrinsic State)的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享的。
3、享元工厂(FlyweightFactory)角色:本角色负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有一个复合要求的享元对象。如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
4、客户端(Client)角色:本角色需要维护一个对所有享元对象的引用。本角色需要自行存储所有享元对象的外蕴状态。


Flyweight.h

#ifndef FLYWEIGHT_H
#define FLYWEIGHT_H
#include <string>
#include <list>
typedef std::string STATE;
class Flyweight
{
public:
    virtual ~Flyweight(){}
    STATE GetIntrinsicState();
    virtual void Operation(STATE& ExtrinsicState) = 0;
protected:
    Flyweight(const STATE& state)
        :m_State(state)
    {
    }
private:
    STATE m_State;
};
class FlyweightFactory
{
public:
    FlyweightFactory(){}
    ~FlyweightFactory();
    Flyweight* GetFlyweight(const STATE& key);
private:
    std::list<Flyweight*>    m_listFlyweight;
};
class ConcreateFlyweight
    : public Flyweight
{
public:
    ConcreateFlyweight(const STATE& state)
        : Flyweight(state)
    {
    }
    virtual ~ConcreateFlyweight(){}
    virtual void Operation(STATE& ExtrinsicState);
};
#endif

Flyweight.cpp

#include "FlyWeight.h"
#include <iostream>
inline STATE Flyweight::GetIntrinsicState()
{
    return m_State;
}
FlyweightFactory::~FlyweightFactory()
{
    std::list<Flyweight*>::iterator iter1, iter2, temp;
    for (iter1 = m_listFlyweight.begin(), iter2 = m_listFlyweight.end();
        iter1 != iter2;
        )
    {
        temp = iter1;
        ++iter1;
        delete (*temp);
    }
    m_listFlyweight.clear();
}
Flyweight* FlyweightFactory::GetFlyweight(const STATE& key)
{
    std::list<Flyweight*>::iterator iter1, iter2;
    for (iter1 = m_listFlyweight.begin(), iter2 = m_listFlyweight.end();
         iter1 != iter2;
         ++iter1)
    {
        if ((*iter1)->GetIntrinsicState() == key)
        {
            std::cout << "The Flyweight:" << key << " already exits"<< std::endl;
            return (*iter1);
        }
    }
    std::cout << "Creating a new Flyweight:" << key << std::endl;
    Flyweight* flyweight = new ConcreateFlyweight(key);
    m_listFlyweight.push_back(flyweight);
}
void ConcreateFlyweight::Operation(STATE& ExtrinsicState)
{
}

main.cpp


#include "FlyWeight.h"
int main()
{
    FlyweightFactory flyweightfactory;
    flyweightfactory.GetFlyweight("hello");
    flyweightfactory.GetFlyweight("world");
    flyweightfactory.GetFlyweight("hello");
    system("pause");
    return 0;
}



<think>我们正在讨论设计模式中的Flyweight模式(享元模式)。根据用户的问题,他之前询问了字面量的定义,但现在转向了Flyweight模式。用户要求定义Flyweight模式,并提供了多个引用。我们需要基于这些引用和已知的设计模式知识来回答。 参考引用: [^1]: C++中的Flyweight设计模式详解。Flyweight模式的实现首先定义了一个Flyweight接口,这个接口通常包含一个或多个纯虚函数,用于执行对象外部状态依赖的操作。 [^2]: 我们先编写一个Flyweight类的定义,它代表一个可共享对象。如下:public abstract class Shape { ... } [^3]: 抽象享元角色(Flyweight):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法。 [^4]: 蝇量工厂(FlyweightFactory):负责管理蝇量对象,形成一个对象池,提供取出对象的方法。 [^5]: 享元模式是一种结构型设计模式,它通过将对象的可共享部分与不可共享部分分离,从而减少重复对象的数量,达到节省内存的目的。 根据这些引用,我们可以总结出Flyweight模式的定义和关键组成部分。 享元模式Flyweight Pattern)是一种结构型设计模式,它通过共享技术来有效支持大量细粒度对象的复用。它通过共享已经存在的对象来减少创建对象的数量,从而减少内存占用和提高性能。 享元模式的核心在于区分内部状态(Intrinsic State)和外部状态(Extrinsic State): - 内部状态:对象中不会随环境改变而改变的部分,这部分状态可以被共享,存储在享元对象内部。 - 外部状态:对象中会随环境改变而改变的部分,这部分状态不能被共享,需要在调用时由外部传入。 享元模式的主要角色包括: 1. 抽象享元角色(Flyweight):定义了一个接口,通过这个接口可以接受并作用于外部状态。 2. 具体享元角色(ConcreteFlyweight):实现抽象享元接口,并为内部状态增加存储空间。该角色必须是可共享的,并且任何状态都应该是内部的。 3. 非共享具体享元角色(UnsharedConcreteFlyweight):并不是所有的享元对象都需要共享,非共享的具体享元角色通常作为组合中的叶节点。 4. 享元工厂角色(FlyweightFactory):负责创建和管理享元对象。它确保合理地共享享元对象,当用户请求一个享元对象时,工厂会检查是否已经存在一个符合要求的享元对象,如果存在则返回,否则创建一个新的。 使用享元模式的典型场景: - 一个应用程序使用大量的对象。 - 大量的对象造成很大的存储开销。 - 对象的大多数状态可以外部化(变为外部状态)。 - 使用享元模式后,由于共享对象,存储开销得以降低。 优点: - 减少内存中对象的数量,节省内存。 - 减少了创建对象的时间,提高性能。 缺点: - 增加了系统的复杂度,需要分离出内部状态和外部状态。 - 外部状态需要由客户端保存,并在使用享元对象时传入,这可能增加系统的逻辑复杂度。 示例代码(基于引用[2]的Shape类): 假设我们有一个图形类,颜色是内部状态,而位置和大小可以是外部状态。 抽象享元角色(Shape): ```java public abstract class Shape { protected String color; // 内部状态(颜色) public Shape(String color) { this.color = color; } public abstract void draw(int x, int y); // 外部状态(坐标) } ``` 具体享元角色(Circle): ```java public class Circle extends Shape { public Circle(String color) { super(color); } @Override public void draw(int x, int y) { System.out.println("Drawing a " + color + " circle at (" + x + "," + y + ")"); } } ``` 享元工厂(ShapeFactory): ```java import java.util.HashMap; import java.util.Map; public class ShapeFactory { private static final Map<String, Shape> circleMap = new HashMap<>(); public static Shape getCircle(String color) { Circle circle = (Circle) circleMap.get(color); if (circle == null) { circle = new Circle(color); circleMap.put(color, circle); System.out.println("Creating circle of color : " + color); } return circle; } } ``` 客户端使用: ```java public class Client { private static final String colors[] = { "Red", "Green", "Blue", "White", "Black" }; public static void main(String[] args) { for (int i = 0; i < 20; ++i) { Circle circle = (Circle) ShapeFactory.getCircle(getRandomColor()); circle.draw(getRandomX(), getRandomY()); } } private static String getRandomColor() { return colors[(int) (Math.random() * colors.length)]; } private static int getRandomX() { return (int) (Math.random() * 100); } private static int getRandomY() { return (int) (Math.random() * 100); } } ``` 在这个例子中,颜色相同的圆会被共享,所以即使我们画出20个圆,实际上创建的圆对象只有颜色种类数(5个)。每个圆的坐标(外部状态)在调用draw方法时传入。 根据引用[5]:享元模式通过分离内部状态和外部状态,共享内部状态,从而达到减少对象数量的目的。 因此,我们给出Flyweight模式的定义: 享元模式Flyweight Pattern)是一种用于减少对象数量、节省内存的结构型设计模式,它通过共享对象来支持大量细粒度对象的复用。 最后,生成相关问题。 注意:用户提供的引用中,引用[1]是C++的,引用[2]是Java的,但设计模式是语言无关的,我们以Java为例进行说明。 </think>### Flyweight模式(享元模式)定义 **Flyweight模式** 是一种结构型设计模式,它通过共享对象来**最小化内存使用**并优化性能,特别适用于存在大量相似对象的场景。该模式的核心思想是分离对象的**内部状态(可共享)** 和**外部状态(不可共享)**,并通过工厂管理共享对象池[^1][^3][^5]。 --- ### 核心概念解析 #### 1. **状态分离原理** - **内部状态(Intrinsic State)** 对象中**固定不变**的部分(如颜色、类型),可被多个对象共享。例如在图形系统中,圆形对象的颜色属性可共享[^2]。 - **外部状态(Extrinsic State)** 对象中**动态变化**的部分(如位置、大小),需由客户端传入。例如绘制圆形时需单独指定坐标[^5]。 #### 2. **关键角色** | 角色 | 功能 | 示例引用 | |----------------------|----------------------------------------------------------------------|--------------------| | **抽象享元(Flyweight)** | 定义共享对象的接口,声明操作外部状态的方法 | `Shape` 抽象类 [^2] | | **具体享元(ConcreteFlyweight)** | 实现抽象接口,存储内部状态(如颜色) | `Circle` 类 [^2] | | **享元工厂(FlyweightFactory)** | 管理对象池:复用已有对象或创建新对象 | 对象池管理 [^4] | | **客户端(Client)** | 维护外部状态,调用享元对象 | 调用 `draw()` [^2] | #### 3. **工作流程** ```mermaid sequenceDiagram Client->>FlyweightFactory: 请求对象(参数:内部状态) FlyweightFactory-->>Client: 返回共享对象 Client->>Flyweight: 执行操作(传入外部状态) Flyweight-->>Client: 返回结果 ``` --- ### 应用示例 #### 场景:图形渲染系统 假设需绘制1000个圆形,颜色只有红、蓝、绿三种。 **传统实现** 创建1000个圆形对象 → 内存占用大。 **Flyweight模式实现** 1. **共享内部状态(颜色)** ```java public abstract class Shape { protected String color; // 内部状态(可共享) public abstract void draw(int x, int y); // 外部状态(坐标) } ``` 2. **具体享元类** ```java public class Circle extends Shape { public Circle(String color) { this.color = color; } @Override public void draw(int x, int y) { System.out.println("Draw " + color + " circle at ("+x+","+y+")"); } } ``` 3. **享元工厂** ```java public class ShapeFactory { private static final Map<String, Shape> pool = new HashMap<>(); public static Shape getCircle(String color) { if (!pool.containsKey(color)) { pool.put(color, new Circle(color)); // 创建新对象 } return pool.get(color); // 返回共享对象 } } ``` 4. **客户端调用** ```java // 仅存储3个共享对象,而非1000个实例 Shape redCircle = ShapeFactory.getCircle("red"); redCircle.draw(10, 20); // 传入外部状态(坐标) ``` --- ### 模式价值与适用场景 | 优势 | 适用场景 | |-------------------------------|----------------------------------| | ✅ 减少内存占用(对象复用) | 大量相似对象的系统(如游戏粒子) | | ✅ 提升性能(避免重复创建) | 文本编辑器中的字符渲染 | | ✅ 解耦内部/外部状态 | 图形用户界面组件库 | | 局限性 | |-------------------------------| | ⚠️ 增加系统复杂度(状态分离) | | ️ 线程安全问题(共享对象池) | > 🔍 **总结**:Flyweight模式通过分离**可共享的固有属性**和**需外部传入的动态属性**,实现对象复用,解决海量细粒度对象的内存消耗问题[^5]。 ```mermaid graph LR A[客户端] -->|请求对象| B[享元工厂] B -->|对象存在| C[返回共享对象] B -->|对象不存在| D[创建新对象存入池] C --> E[具体享元] D --> E E -->|操作| F[使用外部状态] ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值