1.简介
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
我们这里新建H、E、L、O四个类,每个类返回对应的字母,用来打印HELLO。
首先,新建一个抽象类,用来规定H、E、L、O四个类需要有相同的操作DisPlay
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FlyweightPattern { public abstract class BaseWord { public abstract string DisPlay(); } }
H类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace FlyweightPattern { class H:BaseWord { public H() { Thread.Sleep(500); Console.WriteLine("字母H被构造"); } public override string DisPlay() { return "H"; } } }
E类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace FlyweightPattern { class E : BaseWord { public E() { Thread.Sleep(500); Console.WriteLine("字母E被构造"); } public override string DisPlay() { return "E"; } } }
L类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace FlyweightPattern { class L:BaseWord { public L() { Thread.Sleep(500); Console.WriteLine("字母L被构造"); } public override string DisPlay() { return "L"; } } }
O类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace FlyweightPattern { class O:BaseWord { public O() { Thread.Sleep(500); Console.WriteLine("字母O被构造"); } public override string DisPlay() { return "O"; } } }
接下来是享元模式的核心
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FlyweightPattern { public class FlyWeightFactory//享元工厂 { private static Dictionary<WordType, BaseWord> _BaseWorldDictionary = new Dictionary<WordType, BaseWord>();//用字典保存关键字和类的实例 public static BaseWord GetWord(WordType wordType) { BaseWord baseWord = null; if (_BaseWorldDictionary.ContainsKey(wordType))//如果字典中已经有这个实例,就直接使用,没有就新增 { baseWord = _BaseWorldDictionary[wordType]; } else { switch (wordType) { case WordType.E: baseWord = new E(); break; case WordType.H: baseWord = new H(); break; case WordType.L: baseWord = new L(); break; case WordType.O: baseWord = new O(); break; default:throw new Exception("wrong wordType"); } _BaseWorldDictionary.Add(wordType, baseWord); } return baseWord; } } public enum WordType { H,E,L,O } }
Program:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FlyweightPattern { class Program { static void Main(string[] args) { show1(); show2(); Console.Read(); } static void show1() { Console.WriteLine("--------------------show1-----------------------"); BaseWord baseWord1 = FlyWeightFactory.GetWord(WordType.H); BaseWord baseWord2 = FlyWeightFactory.GetWord(WordType.E); BaseWord baseWord3 = FlyWeightFactory.GetWord(WordType.L); BaseWord baseWord4 = FlyWeightFactory.GetWord(WordType.L); BaseWord baseWord5 = FlyWeightFactory.GetWord(WordType.O); Console.Write(baseWord1.DisPlay()); Console.Write(baseWord2.DisPlay()); Console.Write(baseWord3.DisPlay()); Console.Write(baseWord4.DisPlay()); Console.Write(baseWord5.DisPlay()); Console.WriteLine(); } static void show2() { Console.WriteLine("--------------------show2-----------------------"); BaseWord baseWord1 = FlyWeightFactory.GetWord(WordType.H); BaseWord baseWord2 = FlyWeightFactory.GetWord(WordType.E); BaseWord baseWord3 = FlyWeightFactory.GetWord(WordType.L); BaseWord baseWord4 = FlyWeightFactory.GetWord(WordType.L); BaseWord baseWord5 = FlyWeightFactory.GetWord(WordType.O); Console.Write(baseWord1.DisPlay()); Console.Write(baseWord2.DisPlay()); Console.Write(baseWord3.DisPlay()); Console.Write(baseWord4.DisPlay()); Console.Write(baseWord5.DisPlay()); Console.WriteLine(); } } }
2.多线程享元模式
当我们使用多线程的时候,上面的例子并不稳定
很大可能会发生错误
对Program的Main函数进行修改,启用多线程
static void Main(string[] args) { new Action(show1).BeginInvoke(null, null); new Action(show2).BeginInvoke(null, null); Console.Read(); }
执行的时候两个线程会同步进行
结果如下:
H类被实例化了两次,字典添加相同的键,发生错误
可以对享元工厂进行双if+lock锁来解决这个问题
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace FlyweightPattern { public class FlyWeightFactory//享元工厂 { static object FlyWeight_Lock = new object();//定义一个静态object参数,用来做lock的参数 private static Dictionary<WordType, BaseWord> _BaseWorldDictionary = new Dictionary<WordType, BaseWord>();//用字典保存关键字和类的实例 public static BaseWord GetWord(WordType wordType) { BaseWord baseWord = null; if (_BaseWorldDictionary.ContainsKey(wordType)) { baseWord = _BaseWorldDictionary[wordType]; } else { lock (FlyWeight_Lock) { if (_BaseWorldDictionary.ContainsKey(wordType))//如果字典中已经有这个实力,就直接使用,没有就新增 { baseWord = _BaseWorldDictionary[wordType]; } else { switch (wordType) { case WordType.E: baseWord = new E(); break; case WordType.H: baseWord = new H(); break; case WordType.L: baseWord = new L(); break; case WordType.O: baseWord = new O(); break; default: throw new Exception("wrong wordType"); } _BaseWorldDictionary.Add(wordType, baseWord); } } } return baseWord; } } public enum WordType { H,E,L,O } }
执行结果:
因为多线程的无序性,打印结果并不是我们期待的结果
可以对打印代码进行一下修改
修改为:
结果: