享元模式(Flyweight)

First Post:

Last Update:

享元模式(Flyweight)

享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。

享元模式结构图

享元模式成员分析

没看懂,也许后面会更新罢。

享元模式代码结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/// FlyWeight类,它是所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。
abstract class Flyweight
{
public abstract void Operation(int extrinsicstate);
}

/// ConcreteFlyweight类是继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间
class ConcreteFlyweight : Flyweight
{
public override void Operation(int extrinsicstate)
{
Console.Write("具体的Flyweight" + extrinsicstate);
}
}

class UnsharedConcreteFlyweight : Flyweight
{
public override void Operation(int extrinsicstate)
{
Console.WriteLine("不共享的具体Flyweight" + extrinsicstate);
}
}

/// FlyweightFactory类,是一个享元工厂,用来创建并管理Flyweight对象。
/// 它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,
/// FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
class FlyweightFactory
{
private Hashtable flyweights = new Hashtable();
//初始化工厂时,生成3个实例
public FlyweightFactory()
{
flyweights.Add("x", new ConcreteFlyweight());
flyweights.Add("y", new ConcreteFlyweight());
flyweights.Add("z", new ConcreteFlyweight());
}
//根据客户端的请求,获得已生成的实例
public Flyweight GetFlyweight(string key)
{
return (Flyweight)flyweights[key];
}
}

享元模式总结

问题:

一定要在工厂里面事先实例化对象实例嘛?

不一定,可以在工厂实例化时什么都不做,到需要使用时,再判断GetFlyweight(key)是否为null,是则实例化一个对象实例。

Unshared的享元存在的意义何在?

有一些时候的特例,有可能存在不需要共享的实例对象。

关键

内部状态和外部状态

享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本相同,有时就能够大幅度地减少需要实例化的类的数量。如果能够把那些参数移到类实例的外面,在方法调用时再将它们传递进来,就可以通过共享去大幅度地减少单个实例的数目。

内部状态存储在具体享元当中

将外部状态作为方法参数存放于具体享元的方法中

考虑将外部状态放在客户端中存储或计算。

享元模式应用场景

如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时,应该考虑使用享元模式。

此外,如果对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。

游戏开发中的享元模式

享元模式用于在多个对象之间共享相同的数据。

例如,游戏场景中的一些植被和重复得小物件,它们的贴图或是网格都是一样的,可以创建一个公共的对象来记录这些数据,我称之为共享数据,然后他们的位置,朝向可能都不一样,这些数据我称之为私有数据。

如我们要在游戏场景中绘制1k棵树,在未使用享元模式之前:

1
2
3
4
5
6
7
8
9
10
11
12
class Tree

private:
Mesh mesh_;
Texture bark_;
Texture leaves_;
Vector position_;
double height_;
double thickness_;
Color barkTint_;
Color leafTint_;
};

使用享元模式之后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class TreeModel

private:
Mesh mesh_;
Texture bark_;
Texture leaves_;
};
class Tree

private:
TreeModel* model_;
Vector position_;
double height_;
double thickness_;
Color barkTint_;
Color leafTint_;
};

这样我们就只需要创建一个Model对象,让所有的树都引用这份数据,而不是每棵树都拥有自己的网格数据,可以节约内存。以上例子来源于《游戏设计模式》。

使用享元模式的前提是,他们的数据必须是可以共享的,即有相同的数据。