享元模式的定义为我们提出了两个要求:细粒度的对象和共享对象。
要求细粒度对象,那么不可避免地使得对象数量多且性质相近,那我们就将这些对象的信息分为两个部分:内部状态(intrinsic)与外部状态(extrinsic)。
如果分配太多的对象到应用程序中将有损程序的性能,同时还容易造成内存溢出。那怎么避免呢?就是享元模式中提到的共享技术。
Flyweight抽象享元角色
它简单地说就是一个产品的抽象类,同时定义出对对象的外部状态和内部状态的接口或实现
ConcreteFlyweight具体享元角色
具体的一个产品类,实现抽象角色定义的业务。该角色中需要注意的是内部状态处理应该与环境无关,不应该出现一个操作改变了内部状态,同时修改了外部状态,这是绝对不允许的。
UnsharedConcreteFlyweight不可共享的享元角色
不存在外部状态或者安全要求(如线程安全)不能够使用共享技术的对象,该对象一般不会出现在享元工厂中。
FlyweightFactory享元工厂
职责非常简单,就是构造一个池容器,同时提供从池中获得对象的方法。
Flyweight类,它是所有具体的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态
abstract class Flyweight
{
public abstract void Operation(int extrinsicstate);
}
ConcreteFlyweight是继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间
class ConcreteFlyweight : Flyweight
{
public override void Operation(int extrinsicstate)
{
Console.WriteLine("具体Flyweight:"+extrinsicstate);
}
}
UnsharedConcreteFlyweight是指那些不需要共享的Flywei子类。因为Flyweig接口共享成为可能,但它并不强制共享
class UnsharedConcreteweight : Flyweight
{
public override void Operation(int extrinsicstate)
{
Console.WriteLine("不共享的具体Flyweight:"+extrinsicstate);
}
}
FlyweigFacory,是一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)
class FlyweihtFactory
{
private Hashtable flyweithts = new Hashtable();
public FlyweihtFactory()
{
flyweithts.Add("X", new ConcreteFlyweight()); //初始化工厂时,先生成三个实例
flyweithts.Add("Y", new ConcreteFlyweight());
flyweithts.Add("Z", new ConcreteFlyweight());
}
public Flyweight GetFlyweight(string key) //根据客户端请求,获得已生成的实例
{
return ((Flyweight)flyweithts[key]);
}
}
客户端代码
static void Main(string[] args)
{
int extrinsicstate = 22; //代码外部状态
FlyweihtFactory f = new FlyweihtFactory();
Flyweight fx = f.GetFlyweight("X");
fx.Operation(--extrinsicstate);
Flyweight fy = f.GetFlyweight("Y");
fy.Operation(--extrinsicstate);
Flyweight fz = f.GetFlyweight("Z");
fz.Operation(--extrinsicstate);
Flyweight uf = new UnsharedConcreteweight();
uf.Operation(--extrinsicstate);
Console.Read();
}
用户类, 用于网站的客户账号,是“网站”类的外部状态
用户
public class User
{
private string name;
public User(string name)
{
this.name = name;
}
public string Name
{
get { return name; }
}
}
网站抽象类
abstract class WebSite
{
public abstract void Use(User user); //“使用”方法需要传递“用户”对象
}
具体网站类
class ConcreteWebSite : WebSite
{
private string name = "";
public ConcreteWebSite(string name)
{
this.name = name;
}
public override void Use(User user) //实现"Use"方法
{
Console.WriteLine("网站分类:"+name+"用户:"+ user.Name);
}
}
网站工厂类
class WebSiteFactory
{
private Hashtable flyweights=new Hashtable();
//获得网站分类
public WebSite GetWebSiteCategory(string key)
{
if (!flyweights.ContainsKey(key))
flyweights.Add(key, new ConcreteWebSite(key));
return ((WebSite)flyweights[key]);
}
//获得网站分类总数
public int GetWebSiteCount()
{
return flyweights.Count;
}
}
客户端代码
static void Main(string[] args)
{
WebSiteFactory f = new WebSiteFactory();
WebSite fx = f.GetWebSiteCategory("产品展示");
fx.Use(new User("小菜"));
WebSite fy = f.GetWebSiteCategory("产品展示");
fy.Use(new User("大鸟"));
WebSite fz = f.GetWebSiteCategory("产品展示");
fz.Use(new User("娇娇"));
WebSite f1 = f.GetWebSiteCategory("博客");
f1.Use(new User("老顽童"));
WebSite f2 = f.GetWebSiteCategory("博客");
f2.Use(new User("桃谷六仙"));
WebSite f3 = f.GetWebSiteCategory("博客");
f3.Use(new User("南海神鳄"));
Console.WriteLine("得到的网站分类总数 {0}", f.GetWebSiteCount());
Console.Read();
}
享元模式可以大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能
提高了系统的复杂性,需要分离出外部状态和内部状态,而且外部状态具有固化特征,不应该随内部状态改变而改变,否则导致系统的逻辑混乱
1.系统中存在大量的相似对象
2.细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份
3.需要缓冲池的场景
享元模式的目的在于运用共享技术,使得一些细粒度的对象可以共享,我们的设计确实也应该这样,多使用细粒度对象,便于重用或重构。