目录
享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少创建大量相似对象所需的内存消耗。它通过共享尽可能多的数据来达到最大化地复用细粒度的对象。享元模式适用于需要创建大量相似对象的情况,这些对象大多数是细粒度的,并且可以共享某些部分的信息。
享元模式的关键组成部分
- 享元接口(Flyweight):定义了所有具体享元类的公共接口。
- 具体享元类(Concrete Flyweights):实现享元接口,并且每个享元存储内部状态的一部分。
- 非享元对象(Unshared Concrete Flyweights):存储外部状态,这些状态不能共享。
- 享元工厂(Flyweight Factory):负责创建和管理享元对象。
享元模式的应用场景
享元模式适用于以下情况:
- 对象的大部分状态可以外部化。
- 许多对象的结构几乎相同,只是某些个别属性不同。
- 由于使用了大量的细粒度对象,导致内存消耗过大。
享元模式的实现步骤
- 定义享元接口。
- 实现具体享元类。
- 实现享元工厂类。
- 使用享元工厂来获取具体的享元对象,并传递外部状态。
享元模式的示例
假设我们在开发一个绘图应用,需要绘制大量的圆圈。由于圆圈的颜色和位置可能不同,但我们希望共享尽可能多的信息,以减少内存消耗。
步骤1:定义享元接口
c
深色版本
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5typedef struct Circle {
6 void (*draw)(struct Circle *circle, int x, int y);
7} Circle;
8
9void drawCircle(Circle *circle, int x, int y) {
10 printf("Drawing circle at (%d, %d)\n", x, y);
11}
步骤2:实现具体享元类
在这个例子中,我们将根据颜色创建不同的享元对象。颜色作为内部状态,而位置作为外部状态。
c
深色版本
1typedef struct ColorCircle {
2 Circle base;
3 char color[20];
4} ColorCircle;
5
6ColorCircle* createColorCircle(const char *color) {
7 ColorCircle *circle = (ColorCircle *)malloc(sizeof(ColorCircle));
8 strcpy(circle->color, color);
9 circle->base.draw = drawColorCircle;
10 return circle;
11}
12
13void drawColorCircle(Circle *circle, int x, int y) {
14 ColorCircle *colorCircle = (ColorCircle *)circle;
15 printf("Drawing %s circle at (%d, %d)\n", colorCircle->color, x, y);
16}
17
18void destroyColorCircle(ColorCircle *circle) {
19 free(circle);
20}
步骤3:实现享元工厂类
享元工厂负责创建和管理享元对象,并确保相同的享元对象不会被重复创建。
c
深色版本
1typedef struct CircleFactory {
2 ColorCircle *circles[100]; // 假设最多有100个不同的颜色
3 int count;
4} CircleFactory;
5
6CircleFactory* createCircleFactory() {
7 CircleFactory *factory = (CircleFactory *)malloc(sizeof(CircleFactory));
8 factory->count = 0;
9 return factory;
10}
11
12Circle* getCircle(CircleFactory *factory, const char *color) {
13 for (int i = 0; i < factory->count; ++i) {
14 if (strcmp(factory->circles[i]->color, color) == 0) {
15 return &(factory->circles[i]->base);
16 }
17 }
18
19 // 如果没有找到,则创建一个新的享元对象
20 if (factory->count < 100) {
21 factory->circles[factory->count] = createColorCircle(color);
22 factory->count++;
23 return &(factory->circles[factory->count - 1]->base);
24 }
25
26 // 如果超过最大数量,可以选择其他处理方式
27 return NULL;
28}
29
30void destroyCircleFactory(CircleFactory *factory) {
31 for (int i = 0; i < factory->count; ++i) {
32 destroyColorCircle(factory->circles[i]);
33 }
34 free(factory);
35}
步骤4:客户端代码
c
深色版本
1int main() {
2 CircleFactory *circleFactory = createCircleFactory();
3
4 Circle *redCircle = getCircle(circleFactory, "red");
5 Circle *blueCircle = getCircle(circleFactory, "blue");
6 Circle *greenCircle = getCircle(circleFactory, "green");
7
8 drawCircle(redCircle, 10, 20);
9 drawCircle(blueCircle, 30, 40);
10 drawCircle(greenCircle, 50, 60);
11
12 // 再次获取,应该返回同一个对象
13 Circle *anotherRedCircle = getCircle(circleFactory, "red");
14 drawCircle(anotherRedCircle, 70, 80);
15
16 destroyCircleFactory(circleFactory);
17
18 return 0;
19}
运行结果
当你运行上述 main
函数时,你会看到以下输出:
深色版本
1Drawing red circle at (10, 20)
2Drawing blue circle at (30, 40)
3Drawing green circle at (50, 60)
4Drawing red circle at (70, 80)
解释
在这个例子中,CircleFactory
负责创建和管理 ColorCircle
对象。每次调用 getCircle
方法时,工厂都会检查是否已经有对应的 ColorCircle
对象存在,如果有则直接返回,否则创建一个新的对象。通过这种方式,我们可以避免重复创建相同颜色的圆圈对象,从而节省内存。
享元模式的优点
- 内存优化:通过共享部分数据,可以显著减少内存消耗。
- 性能提升:由于减少了对象的创建,性能有所提升。
- 代码清晰:通过工厂模式管理享元对象,代码更加清晰。
享元模式的缺点
- 复杂度增加:需要额外的管理机制来确保享元对象的正确创建和共享。
- 外部状态管理:享元模式需要外部状态管理,这可能会增加代码的复杂度。
总结
享元模式通过共享部分数据来减少内存消耗,并且适用于需要创建大量相似对象的场景。在设计系统时,如果发现有大量的细粒度对象,并且其中有很多可以共享的部分,可以考虑使用享元模式来优化内存使用和提高性能。