在软件开发过程,如果我们需要重复使用某个对象的时候,如果我们重复地使用new创建这个对象的话,这样我们在内存就需要多次地去申请内存空间了,这样可能会出现内存使用越来越多的情况,这样的问题是非常严重,然而享元模式可以解决这个问题。
享元模式——运用共享技术有效地支持大量细粒度的对象。享元模式可以避免大量相似类的开销,在软件开发中如果需要生成大量细粒度的类实例来表示数据,如果这些实例除了几个参数外基本上都是相同的,这时候就可以使用享元模式来大幅度减少需要实例化类的数量。如果能把这些参数(指的这些类实例不同的参数)移动类实例外面,在方法调用时将他们传递进来,这样就可以通过共享大幅度地减少单个实例的数目。(这个也是享元模式的实现要领),然而我们把类实例外面的参数称为享元对象的外部状态,把在享元对象内部定义称为内部状态。具体享元对象的内部状态与外部状态的定义为:
内部状态:在享元对象的内部并且不会随着环境的改变而改变的共享部分
外部状态:随环境改变而改变的,不可以共享的状态。
1 /// <summary> 2 /// 客户端调用 3 /// </summary> 4 class Client 5 { 6 static void Main(string[] args) 7 { 8 // 定义外部状态,例如字母的位置等信息 9 int externalstate = 10; 10 // 初始化享元工厂 11 FlyweightFactory factory = new FlyweightFactory(); 12 13 // 判断是否已经创建了字母A,如果已经创建就直接使用创建的对象A 14 Flyweight fa = factory.GetFlyweight("A"); 15 if (fa != null) 16 { 17 // 把外部状态作为享元对象的方法调用参数 18 fa.Operation(--externalstate); 19 } 20 // 判断是否已经创建了字母B 21 Flyweight fb = factory.GetFlyweight("B"); 22 if (fb != null) 23 { 24 fb.Operation(--externalstate); 25 } 26 // 判断是否已经创建了字母C 27 Flyweight fc = factory.GetFlyweight("C"); 28 if (fc != null) 29 { 30 fc.Operation(--externalstate); 31 } 32 // 判断是否已经创建了字母D 33 Flyweight fd= factory.GetFlyweight("D"); 34 if (fd != null) 35 { 36 fd.Operation(--externalstate); 37 } 38 else 39 { 40 Console.WriteLine("驻留池中不存在字符串D"); 41 // 这时候就需要创建一个对象并放入驻留池中 42 ConcreteFlyweight d = new ConcreteFlyweight("D"); 43 factory.flyweights.Add("D", d); 44 } 45 46 Console.Read(); 47 } 48 } 49 50 /// <summary> 51 /// 享元工厂,负责创建和管理享元对象 52 /// </summary> 53 public class FlyweightFactory 54 { 55 // 最好使用泛型Dictionary<string,Flyweighy> 56 //public Dictionary<string, Flyweight> flyweights = new Dictionary<string, Flyweight>(); 57 public Hashtable flyweights = new Hashtable(); 58 59 public FlyweightFactory() 60 { 61 flyweights.Add("A", new ConcreteFlyweight("A")); 62 flyweights.Add("B", new ConcreteFlyweight("B")); 63 flyweights.Add("C", new ConcreteFlyweight("C")); 64 } 65 66 public Flyweight GetFlyweight(string key) 67 { 68 // 更好的实现如下 69 //Flyweight flyweight = flyweights[key] as Flyweight; 70 //if (flyweight == null) 71 //{ 72 // Console.WriteLine("驻留池中不存在字符串" + key); 73 // flyweight = new ConcreteFlyweight(key); 74 //} 75 //return flyweight; 76 return flyweights[key] as Flyweight; 77 } 78 } 79 80 /// <summary> 81 /// 抽象享元类,提供具体享元类具有的方法 82 /// </summary> 83 public abstract class Flyweight 84 { 85 public abstract void Operation(int extrinsicstate); 86 } 87 88 // 具体的享元对象,这样我们不把每个字母设计成一个单独的类了,而是作为把共享的字母作为享元对象的内部状态 89 public class ConcreteFlyweight : Flyweight 90 { 91 // 内部状态 92 private string intrinsicstate ; 93 94 // 构造函数 95 public ConcreteFlyweight(string innerState) 96 { 97 this.intrinsicstate = innerState; 98 } 99 100 /// <summary> 101 /// 享元类的实例方法 102 /// </summary> 103 /// <param name="extrinsicstate">外部状态</param> 104 public override void Operation(int extrinsicstate) 105 { 106 Console.WriteLine("具体实现类: intrinsicstate {0}, extrinsicstate {1}", intrinsicstate, extrinsicstate); 107 } 108 }
抽象享元角色(Flyweight):此角色是所有的具体享元类的基类,为这些类规定出需要实现的公共接口。那些需要外部状态的操作可以通过调用方法以参数形式传入。
具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的接口。如果有内部状态的话,可以在类内部定义。
享元工厂角色(FlyweightFactory):本角色复杂创建和管理享元角色。本角色必须保证享元对象可以被系统适当地共享,当一个客户端对象调用一个享元对象的时候,享元工厂角色检查系统中是否已经有一个符合要求的享元对象,如果已经存在,享元工厂角色就提供已存在的享元对象,如果系统中没有一个符合的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
客户端角色(Client):本角色需要存储所有享元对象的外部状态。
享元模式主要用来解决由于大量的细粒度对象所造成的内存开销的问题,它在实际的开发中并不常用,可以作为底层的提升性能的一种手段。
学习于 https://www.cnblogs.com/zhili/p/FlyweightPattern.html