设计模式之-享元模式
定义:
享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。
享元模式参与者
- Flyweight:所有具体享元类的超类或接口,通过这个超类或接口,Flyweight可以接受并作用于外部状态。
- FlyweightFactory:享元工厂,用来创建并管理Flyweight,当用户请求一个Flyweight时,FlyweightFactory提供一个已创建的实例或者创建一个(如果不存在)。
- ConcreteFlyweight:继承Flyweight超类或实现Flyweight接口。
- UnsharedConcreteFlyweight:指那些不需要共享的Flyweight子类。
享元模式基本代码
Flyweight类:
namespace FlyweightPattern.BasicStructure { abstract class Flyweight { public abstract void Operation(int extrinsicState); } }
ConcreteFlyweight类:
namespace FlyweightPattern.BasicStructure { class ConcreteFlyweight : Flyweight { public override void Operation(int extrinsicState) { Console.WriteLine("具体Flyweight:" + extrinsicState); } } }
UnSharedConcreteFlyweight类:
namespace FlyweightPattern.BasicStructure { class UnSharedConcreteFlyweight : Flyweight { public override void Operation(int extrinsicState) { Console.WriteLine("不共享的具体Flyweight:" + extrinsicState); } } }
FlyweightFactory类:
namespace FlyweightPattern.BasicStructure { 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]; } } }
客户端调用代码:
static void Main(string[] args) { try { {//BasicStructure int extrinsicState = 22; FlyweightFactory flyweightFactory = new FlyweightFactory(); var flyweight = flyweightFactory.GetFlyweight("X"); flyweight.Operation(--extrinsicState); flyweight = flyweightFactory.GetFlyweight("Y"); flyweight.Operation(--extrinsicState); flyweight = flyweightFactory.GetFlyweight("Z"); flyweight.Operation(--extrinsicState); UnSharedConcreteFlyweight uf = new UnSharedConcreteFlyweight(); uf.Operation(--extrinsicState); } } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.ReadKey(); }
结果如下:
用外观模式实现网站共享代码
场景模拟:由于多个客户需要做网站,其中有一些客户的网站是基本一样的,只有数据不一样。
WebSite(网站抽象)类——Flyweight类
namespace FlyweightPattern.SituationSimulation { /// <summary> /// 网站抽象类 /// </summary> abstract class WebSite { public abstract void Use(); } }
ConcreteWebSite(具体网站)类——ConcreteFlyweight类
namespace FlyweightPattern.SituationSimulation { /// <summary> /// 具体网站类 /// </summary> class ConcreteWebSite : WebSite { public string Name { get; } public ConcreteWebSite(string name) { this.Name = name; } public override void Use() { Console.WriteLine("网站分类:" + Name); } } }
WebSiteFactory(网站工厂)类——FlyweightFactory类
namespace FlyweightPattern.SituationSimulation { 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) { try { {//SituationSimulation WebSiteFactory webSiteFactory = new WebSiteFactory(); var fx = webSiteFactory.GetWebSiteCategory("产品展示"); fx.Use(); var fy = webSiteFactory.GetWebSiteCategory("产品展示"); fy.Use(); var fz = webSiteFactory.GetWebSiteCategory("产品展示"); fz.Use(); var fl = webSiteFactory.GetWebSiteCategory("博客"); fl.Use(); var fm = webSiteFactory.GetWebSiteCategory("博客"); fm.Use(); var fn = webSiteFactory.GetWebSiteCategory("博客"); fn.Use(); Console.WriteLine($"网站分类总数为:{webSiteFactory.GetWebSiteCount()}"); } } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.ReadKey(); }
结果如下:
优点:
享元模式的优点
- 享元模式的优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
- 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
缺点:
享元模式的缺点
- 享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
- 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
适用环境:
在以下情况下可以使用享元模式:
- 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。
- 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
- 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。
总结:
- 享元模式运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用,它是一种对象结构型模式。
- 享元模式包含四个角色:抽象享元类声明一个接口,通过它可以接受并作用于外部状态;具体享元类实现了抽象享元接口,其实例称为享元对象;非共享具体享元是不能被共享的抽象享元类的子类;享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中。
- 享元模式以共享的方式高效地支持大量的细粒度对象,享元对象能做到共享的关键是区分内部状态和外部状态。其中内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,因此内部状态可以共享;外部状态是随环境改变而改变的、不可以共享的状态。
- 享元模式主要优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份;其缺点是使得系统更加复杂,并且需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
- 享元模式适用情况包括:一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费;对象的大部分状态都可以外部化,可以将这些外部状态传入对象中;多次重复使用享元对象。