享元模式 : “使用共享以高效地支持大量的细粒度对象”。
享元模式和单例模式有很多相似的地方,其不同的地方在于:
① , 单例模式在类的内部实现了类的共享,而享元模式是在类的外部实现了类的共享。
② , 享元模式可生成大量相似的对象 , 而单例模式只能生成大量相同的对象。
好了,进入正题 , ,现在用C#代码来实现及解释享元模式:
第一点 : 既然享元模式要实现大量的相似的对象,势必要使用OPO的三大特性之一的继承模式。本节以游戏三种粒子为例( 圆形 circular , 三角形 triangle , 矩形 rectangle )
各个粒子的基类( 抽象类 )
using System;using System.Collections.Generic;using System.Linq;using System.Runtime.CompilerServices;using System.Text;using System.Threading;namespace FlyweightDemo.demo{ ////// 粒子的抽象类 /// public abstract class BaseParticle { protected Type_Particle _type; public BaseParticle( Type_Particle type ) { this._type = type; Thread.Sleep(1000);//模拟初始化的时间 Console.WriteLine("初始化{0}成功!" , ParticleType.description( this._type)); } public abstract void Show(); }}
Thread.Sleep(1000);//模拟初始化的时间 , 所有粒子的初始化时间都比较长
Type_Particle 实际上是一个枚举 , ParticleType.description获得此枚举的描述->如[Description("圆形")]的圆形
using System;using System.Collections.Generic;using System.ComponentModel;using System.Linq;using System.Reflection;using System.Text;namespace FlyweightDemo.demo{ ////// 粒子形状的枚举 /// public enum Type_Particle : uint { [Description("圆形")] circular = 0, [Description("三角形")] triangle = 1, [Description("矩形")] rectangle = 2 } ////// 粒子枚举管理类 /// public static class ParticleType { ////// 获取描述信息 /// /// ///public static string description(this Enum en) { Type type = en.GetType(); MemberInfo[] memInfo = type.GetMember(en.ToString()); if (memInfo != null && memInfo.Length > 0) { object[] attrs = memInfo[0].GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false); if (attrs != null && attrs.Length > 0) return ((DescriptionAttribute)attrs[0]).Description; } return en.ToString(); } }}
现在实现子类,如圆形( 继承抽象类 : BaseParticle )
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace FlyweightDemo.demo{ ////// 圆形粒子 /// public sealed class CircularParticle : BaseParticle { public CircularParticle() : base(Type_Particle.circular) { } ////// 显示例子 /// public override void Show() { Console.WriteLine( ParticleType.description( this._type ) ); //处理圆形粒子特性 } }}
在每个粒子子类的Show中,都可以对此粒子的特异性做出特殊的处理,这一点有别于单利模式
享元模式的重点 , 获取各种粒子 , 有点想简单工厂模式 。实际上运用了OPO三大特性之一的多态
using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace FlyweightDemo.demo{ public sealed class FlyWeightFactory { private static Dictionarydic_2_particles = new Dictionary (); private static Object particle_lock = new object(); /// /// 获取粒子(可以应对多线程) /// /// 粒子枚举 ///public static BaseParticle GetParticle(Type_Particle type) { if (dic_2_particles.ContainsKey(type)) { return dic_2_particles[type]; } else { lock (particle_lock) { if (dic_2_particles.ContainsKey(type)) { return dic_2_particles[type]; } else { BaseParticle targer_particle = null; switch (type) { case Type_Particle.circular: targer_particle = new CircularParticle(); break; case Type_Particle.triangle: targer_particle = new TriangleParticle(); break; case Type_Particle.rectangle: targer_particle = new RectangleParticle(); break; } if (targer_particle != null) { dic_2_particles[type] = targer_particle; return targer_particle; } return null; } } } } }}
重点:
①,用一个集合来保存所有初始化的粒子
②,所有的粒子只在第一次调用的时候初始化,然后保存到集合中
我们来测试一下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using FlyweightDemo.demo;namespace FlyweightDemo{ public class Program { private object _base_particel = new object(); static void Main(string[] args) { Program a = new Program(); Thread a1 = new Thread(new ThreadStart(a.Show_Eff_One)); Thread a2 = new Thread(new ThreadStart(a.Show_Eff_Two)); a1.IsBackground = true; a2.IsBackground = true; a1.Start(); a2.Start(); Console.Read(); } public void Show_Eff_One() { Type_Particle[] arr = new Type_Particle[] { Type_Particle.circular, Type_Particle.circular, Type_Particle.rectangle, Type_Particle.triangle, Type_Particle.triangle, Type_Particle.rectangle }; this.show_eff(arr,"第一种特效: "); } public void Show_Eff_Two() { Type_Particle[] arr = new Type_Particle[] { Type_Particle.rectangle, Type_Particle.triangle, Type_Particle.triangle, Type_Particle.rectangle, Type_Particle.circular, Type_Particle.circular }; this.show_eff(arr, "第二种特效: "); } private void show_eff( Type_Particle[] arr , string name ) { if (arr != null && arr.Length > 0) { foreach (Type_Particle item in arr) { lock (_base_particel) { BaseParticle target_particle = FlyWeightFactory.GetParticle(item); if (target_particle != null) { Console.Write(name); target_particle.Show(); Console.WriteLine("--------------------------------------------------------------------------"); } } } } } }}
结果如下 :
可以看到所有类型的粒子只初始化了一次 , 第二次调用此粒子就是使用的缓存。
实际上打印结果的时候 , 初始化粒子的时候得1s+( 有一种顿挫的感觉 ) , 而直接使用缓存就非常顺滑。
享元模式应用场景 :
当应用程序初始化时 , 不想加载这些粒子( 因为这么多的粒子很耗时间 , 或者有时候使用者根本不使用这些个粒子 ) , 那么我们就可以使用享元模式,保证应用程序整体的流畅性(使用才加载(并缓存),不使用不加载。