享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象。
Flyweight是一个共享对象,它可以同时在多个场景(context)中使用,并且在每个场景中flyweight都可以作为一个独立的对象—这一点与非共享对象的实例没有区别。flyweight不能对它所运行的场景做出任何假设,这里的关键概念是内部状态和外部状态之间的区别。内部状态存储于flyweight中,它包含了独立于flyweight场景的信息,这些信息使得flyweight可以被共享。而外部状态取决于flyweight场景,并根据场景而变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给flyweight。Flyweight模式对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模
结构
ConcreteFlyweight
——实现Flyweight接口,并为内部状态(如果有的话)增加存储空间。
ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。
UnsharedConcreteFlyweight
——并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。
FlyweightFactory
——创建并管理flyweight对象。
——确保合理地共享flyweight。当用户请求一个flyweigh时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话) 。
Client
——维持一个对flyweight的引用。
——计算或存储一个(多个)flyweight的外部状态。
协作
flyweight执行时所需的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象之中;而外部对象则由Client对象存储或计算。当用户调用flyweight对象的操作时,将该状态传递给它。用户不应直接对ConcreteFlyweight类进行实例化,而应从FlyweightFactory对象得到ConcreteFlyweight对象,这可以保证对它们适当地进行共享。
效果
可以用两种方法来节约存储:用共享减少内部状态的消耗,用计算时间换取对外部状态的存储。(空间换时间)
使用享元模式需要维护一个记录了系统已有的所有享元的列表,而这本身需要消耗资源,另外享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
实现
1)删除外部状态;
2)管理共享对象。
Flyweight是一个共享对象,它可以同时在多个场景(context)中使用,并且在每个场景中flyweight都可以作为一个独立的对象—这一点与非共享对象的实例没有区别。flyweight不能对它所运行的场景做出任何假设,这里的关键概念是内部状态和外部状态之间的区别。内部状态存储于flyweight中,它包含了独立于flyweight场景的信息,这些信息使得flyweight可以被共享。而外部状态取决于flyweight场景,并根据场景而变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给flyweight。Flyweight模式对那些通常因为数量太大而难以用对象来表示的概念或实体进行建模
结构
Flyweight
——描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。ConcreteFlyweight
——实现Flyweight接口,并为内部状态(如果有的话)增加存储空间。
ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyweight对象的场景。
UnsharedConcreteFlyweight
——并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyweight对象通常将ConcreteFlyweight对象作为子节点。
FlyweightFactory
——创建并管理flyweight对象。
——确保合理地共享flyweight。当用户请求一个flyweigh时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话) 。
Client
——维持一个对flyweight的引用。
——计算或存储一个(多个)flyweight的外部状态。
协作
flyweight执行时所需的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象之中;而外部对象则由Client对象存储或计算。当用户调用flyweight对象的操作时,将该状态传递给它。用户不应直接对ConcreteFlyweight类进行实例化,而应从FlyweightFactory对象得到ConcreteFlyweight对象,这可以保证对它们适当地进行共享。
效果
可以用两种方法来节约存储:用共享减少内部状态的消耗,用计算时间换取对外部状态的存储。(空间换时间)
使用享元模式需要维护一个记录了系统已有的所有享元的列表,而这本身需要消耗资源,另外享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。
实现
1)删除外部状态;
2)管理共享对象。
参考代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace MyFlyweight
{
abstract class Flyweight
{
public abstract void Operation(int extrinsicState);
}
class ConcreteFlyweight : Flyweight
{
private int intrinsicState = 0;
public override void Operation(int extrinsicState)
{
Console.WriteLine("Concrete flyweight:{0}",
intrinsicState + extrinsicState);
}
}
class UnsharedConcreteFlyweight : Flyweight
{
private int allState = 0;
public override void Operation(int extrinsicState)
{
Console.WriteLine("Unshared concrete flyweight:{0}", extrinsicState);
}
}
class FlyweightFactory
{
private Hashtable flyweights = new Hashtable();
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]);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyFlyweight
{
class Program
{
static void Main(string[] args)
{
int extrinsicState = 23;
FlyweightFactory f = new FlyweightFactory();
Flyweight fx = f.GetFlyweight("X");
fx.Operation(--extrinsicState);
Flyweight fy = f.GetFlyweight("Y");
fy.Operation(--extrinsicState);
Flyweight fz = f.GetFlyweight("Z");
fz.Operation(--extrinsicState);
var uf = new UnsharedConcreteFlyweight();
uf.Operation(--extrinsicState);
Console.ReadKey();
}
}
}
应用
.NET中,string类就是运用了Flyweight模式。
string titleA = "Flyweight pattern";
string titleB = "Flyweight pattern";
Console.WriteLine(Object.ReferenceEquals(titleA, titleB));
参考:《设计模式》、《大话设计模式》