定义
享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象。——《设计模式:可复用面向对象软件的基础》
适用性
Flyweight 模式的有效性很大程度上取决于如何使用它以及在何处使用它。
当以下情况成立时可以使用 Flyweight 模式:
- 一个应用程序使用了大量的对象。
- 完全由于使用大量对象,造成很大的存储开销。
- 对象的大多数状态都可变为外部状态。
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
- 应用程序不依赖于对象标识。
效果
- 存储空间上的节省抵消了传输、查找和计算外部状态时的开销。节约量随着共享状态的增多而增大。
相关模式
- Flyweight 模式通常和 Composite 模式结合起来,用共享叶节点的又向无环图实现一个逻辑上的层次结构。
- 通常,最好用 Flyweight 实现 State 和 Strategy 对象。
使用场景
我们在需要创建大量(例如10^5)的相似的对象时,使用享元模式。反正我从来没有需要创建这么多相似对象的时候,享元模式在真正的应用中用的要比较少,一般是一些底层数据结构使用到。
实现
实现方式(一):使用 FlyweightFactory 管理 Flyweight 对象。
Flyweight 模式的可用性在很大程度上取决于是否易识别外部状态并将它从共享对象中删除。
理想的状况是,外部状态可以由一个单独的对象结构计算得到,且该结构的存储要求非常小。
通常,因为 Flyweight 对象是共享的,用户不能直接对它进行实例化,因为 FlyweightFactory 可以帮助用户查找某个特定的 Flyweight 对象。
共享还意味着某种形式的引用计数和垃圾回收。
代码
namespace FlyweightPattern.Implementation1
{
public abstract class Flyweight
{
public abstract string Identifier { get; }
public abstract void Operation(string extrinsicState);
}
public class ConcreteFlyweight : Flyweight
{
public override string Identifier
{
get { return "hello"; }
}
public override void Operation(string extrinsicState)
{
// do something
}
}
public class FlyweightFactory
{
private Dictionary<string, Flyweight> _pool
= new Dictionary<string, Flyweight>();
public Flyweight CreateFlyweight(string identifier)
{
if (!_pool.ContainsKey(identifier))
{
Flyweight flyweight = new ConcreteFlyweight();
_pool.Add(flyweight.Identifier, flyweight);
}
return _pool[identifier];
}
}
public class Client
{
public void TestCase1()
{
FlyweightFactory factory = new FlyweightFactory();
Flyweight flyweight1 = factory.CreateFlyweight("hello");
Flyweight flyweight2 = factory.CreateFlyweight("hello");
flyweight1.Operation("extrinsic state");
flyweight2.Operation("extrinsic state");
}
}
}
优点
1、可以极大地减少内存中对象的数量,使得相同对宁或相似对象在内存中只保存一份。
2、外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
缺点
1、使得系统更加复杂,需要分离出内部状态和外部状态。