享元(FlyWeight)模式,原意是“轻量级”模式,它用来解决大量相同对象被多次实例化,从而导致内存被大量占用的情况。在有的时候我们要多次使用某个类中的公有实例方法,我们通常的做法是,先new一个该类的实例,然后再调用该类的这个方法,调用完毕后这个类也就变成垃圾。这种调用方式如果出现的频率很高,会在对象生成和内存占用上付出很大的代价,享元模式尽可能多地节省对象的生成次数,让多个对象共用一个缓存中的对象。
享元模式中关键要理解“内蕴状态”(Internal State)和“外蕴状态”(External State)这两个概念。
内蕴状态:存储在享元对象内部,不随着环境改变,要以被诸多对象共享。
外蕴状态:一般由客户端指定,并传入享元对象内部,它随着环境进行变化。
举例:
1、QQ好友管理器:管理并显示每一个好友发来的消息。在聊天的过程中,与一个好友之间的通信联系只通过一个享元对象实现消息的发送与接收,而不是每次发送接收消息都生成一个新的对象。
2、网吧管理软件:在网吧管理软件中,客户机软件向服务器软件发出请求(如:举手、上线解屏、下线锁屏......),服务器软件也会向客户机发出指令(如:远程关机,远程监视......),不管客户端与服务器端发生多少次交互,在服务器端每个客户端只保留一个对象实例,服务器与每个客户端之间通信就是通过该对象来实现的。
结构图:
抽象享元(Flyweight):为具体享元规定出需要实现的公共接口。
具体享元(ConcreteFlyweight):实现抽象享元角色所规定的接口。如果有“内蕴状态”的话,将“内蕴状态”声明为成员变量,从而使享元对象拥用固定的“内蕴状态”。
享元工厂(FlyweightFactory):负责创建和管理享元角色,保证享元对象可以被共享。当一个客户端对象调用一个享元对象的时候,享元工厂角色会检查系统中是否已经有符合要求的享元对象。如果已经有了,享元工厂就应当提供这个现有享元对象;如果系统中没有适当的享元对象,享元工厂角色就应当创建一个合适的享元对象。
客户端(Client):维护一个对所有享元对象的引用。提供与管理享元对象的“外蕴状态”。
结构图的示意代码:
//抽象享元
abstract class FlyWeight
{
//传入外蕴状态
public abstract void Operation(string extrinsicState);
//显示内蕴状态和外蕴状态
public abstract void Show();
}
//具体享元A
class ConcreteFlyWeightA : FlyWeight
{
//内蕴状态变量
private string intrinsicState = "FlyWeightA";
//外蕴状态变量
private string extrinsicState ;
public override void Operation(string extrinsicState)
{
this.extrinsicState = extrinsicState;
}
public override void Show()
{
Console.WriteLine(this.intrinsicState+"\t"+this.extrinsicState);
}
}
//具体享元B
class ConcreteFlyWeightB : FlyWeight
{
//内蕴状态变量
private string intrinsicState = "FlyWeightB";
//外蕴状态变量
private string extrinsicState;
public override void Operation(string extrinsicState)
{
this.extrinsicState = extrinsicState;
}
public override void Show()
{
Console.WriteLine(this.intrinsicState + "\t" + this.extrinsicState);
}
}
//享元工厂,管理享元对象
class FlyWeightFactory
{
//保存享元对象
private Hashtable t = new Hashtable();
public FlyWeightFactory()
{
t.Add("A", new ConcreteFlyWeightA());
t.Add("B",new ConcreteFlyWeightB());
}
//根据传入的内蕴状态,构造或返回享元对象,
public FlyWeight GetFlyWeight(string key)
{
if (t.ContainsKey(key))
{
return (FlyWeight)t[key];
}
return null;
}
}
class Class1
{
public static void Main(string[] args)
{
FlyWeightFactory f = new FlyWeightFactory();
//这里会根据传入的关键字A,返回享元对象A
FlyWeight fw1 = f.GetFlyWeight("A");
fw1.Operation("A's Extinsic State");
fw1.Show();
//这里会根据传入的关键字B,返回享元对象B
FlyWeight fw2 = f.GetFlyWeight("B");
fw2.Operation("B's Extinsic State");
fw2.Show();
//这里会根据传入的关键字A,返回享元对象A
FlyWeight fw3 = f.GetFlyWeight("A");
fw3.Operation("Another A's Extinsic State");
fw3.Show();
}
}
享元模式是一种针对大量细粒度对象有效使用的一种模式。Android中的Message、Parcel和TypedArray都利用了享元模式。以Message为例,类图如下: