享元模式的定义为我们提出了两个要求:细粒度的对象和共享对象。
要求细粒度对象,那么不可避免地使得对象数量多且性质相近,那我们就将这些对象的信息分为两个部分:内部状态(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.需要缓冲池的场景
享元模式的目的在于运用共享技术,使得一些细粒度的对象可以共享,我们的设计确实也应该这样,多使用细粒度对象,便于重用或重构。