今天咱们继续讲述设计模式,今天说起的是享元模式,享——共享。以前不是出现了一系列共享的东西吗?为啥呀,还不就是有些东西每一个人都须要,可是每一个人都去买一个又有点浪费。因此出现共享。话费必定的经济可使用,使用完成以后又归还。这就是享。分享共享。今天讲的享元模式跟这相相似。享元模式——通俗来讲也就是共享最小单元的一种模式。咱们就一块儿看看到底啥是这享元模式吧。html
在软件系统开发中,咱们确定会出现重复使用同一个对象的状况,每次使用都new一个对象出来。这样的话对于内存来讲就须要屡次反复的申请内存了。这样使用内存也就愈来愈多,这会出现大问题的。那么能不能建立new一个对象。而后使用的时候就共同使用一个就行了。这也就是享元模式的含义所在了——共享一个对象。设计模式
运用共享技术有效地支持大量细粒度的对象。安全
看上面的案例图咱们能够发现享元模式主要包含如下部分:编辑器
享元工厂角色:这个角色主要负责建立和管理享元角色。判断是否存在符合要求的享元对象,若是存在则直接拿取,若是不存在的话就会建立一个享元对象并保存。ide
抽象享元角色:这个角色是全部享元角色的基类。提供须要实现的公共接口性能
具体享元角色:继承于抽象享元角色。实现其抽象的接口。this
客户端:负责调用并处理逻辑,且保存多有享元对象的状态spa
在咱们平时使用的编辑器中,会出现不少的字,这些字也是会一直重复出现的。那么咱们如今就试着使用享元模式来对这些字进行处理。这里暂且使用字母代替:线程
namespace Flyweight_Pattern { class FlyweightPattern { } #region 抽象享元角色——抽象公共接口 public abstract class Flyweight { /// <summary> /// 表述输出的位置 /// </summary> /// <param name="externalstate">外在的状态,随着环境改变而改变</param> public abstract void OutInput(int externalstate); } #endregion #region 具体享元角色——实现其具体 public class SpecificFlyweight : Flyweight { private string Innerstate; /// <summary> /// 内部状态接收 /// </summary> /// <param name="innerstate">内部状态</param> public SpecificFlyweight(string innerstate) { this.Innerstate = innerstate; } /// <summary> /// 实现方法 /// </summary> /// <param name="externalstate">外部状态</param> public override void OutInput(int externalstate) { Console.WriteLine($"内部状态:{Innerstate}————外部状态:{externalstate}"); } } #endregion #region 享元工厂角色——对享元角色进行建立及管理的 public class FlyweightFactory { public Dictionary<string, SpecificFlyweight> keyValuePairs = new Dictionary<string, SpecificFlyweight>(); public SpecificFlyweight GetFlyweight(string Key) { SpecificFlyweight specific = null; if (!keyValuePairs.ContainsKey("A")) { Console.WriteLine("暂时未碰见该Key"); keyValuePairs.Add(Key, new SpecificFlyweight(Key)); Console.WriteLine("现已保存该Key"); } else { specific = keyValuePairs[Key] as SpecificFlyweight; } return specific; } } #endregion }
namespace Flyweight_Pattern { class Program { static void Main(string[] args) { ///初始化享元工厂 FlyweightFactory factory = new FlyweightFactory(); while (true) { Console.WriteLine("请输入字符的位置:"); var indexstring = Console.ReadLine(); if (int.TryParse(indexstring, out int index)) { Console.WriteLine("请输入字符:"); string str = Console.ReadLine(); ///判断字符是否建立 Flyweight flyweight = factory.GetFlyweight(str); //若是存在则输出信息 if (flyweight != null) { flyweight.OutInput(index); } } else { Console.WriteLine("请输入数字!"); } Console.WriteLine("结束请输入N"); if (Console.ReadLine()=="N") { break; } } Console.WriteLine("已结束"); Console.ReadLine(); } } }
这里咱们须要注意的是划分好外部状态和内部状态,不然混淆以后可能引发线程安全问题。同时必不可少的是一个工厂对象进行控制。设计
这里咱们解释下在享元模式中的内在状态和外在状态:
内在状态:不随环境的变化而变化,上面例子中无论位置如何变化,A就是A。字母A就是内在状态。
外在状态:会随着环境的变化而变化,上面例子中位置变化因此输出的位置也是不一致的。字母A的位置就是外在状态
对于享元模式来讲其使用场景可分如下四点:
一、系统须要大量类似对象
二、建立这些对象须要花费大量资源
三、状态可分为内在状态和外在状态,能够根据内在状态分为各类组。
四、须要缓冲池的场景
一、享元模式的优势最主要的是极大的减小了系统中对象的建立,下降了内存使用提升了效率
任何东西来讲都是有利有弊的,咱们看下享元模式又存在哪些弊端呢
一、为了使一些对象共享,对对象区分了内在状态和外在状态,使系统逻辑变为复杂了,使系统更加难于理解了。
咱们再看看享元模式和以前咱们有提到过的原型模式和单例模式的一些区别吧。咱们首先回顾下前面所说的原型模式和单例模式:
原型模式:使用原型实例指定建立对象的种类,而后经过拷贝这些原型来建立新的对象。
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
享元模式:运用共享技术有效地支持大量细粒度的对象。
原型模式——享元模式
咱们再来分析,原型模式是经过原型实例指定建立对象。达到类的复用。经过深浅拷贝类来实现复用以节约资源开销。再看享元模式抽出类似的一些对象,定义其内在状态和外在状态来达到对象共享。运用共享的技术来支持大量细粒度的对象。也就是前面更倾向于实现复用,而享元模式更加倾向于共享使用。因此也不适合放一块儿进行比较的。
单例模式——享元模式
咱们再看单例模式,单例模式保证的是类仅有一个实例,而后提供一个全局访问点,全部访问均可以访问获得。达到的是一个实例数据的共享。咱们再看享元模式,享元模式经过的是将类似的对象进行共享,而后控制内在状态和外在状态来达到变化。享元模式是对象级别的,也就是实现的是多个对象——对象池。而单例模式是一类一个对象的实例。享元模式更加注重的是节约内存空间,提升其性能。然而单例模式注重的是数据的共享。
今天的享元模式就暂时介绍的这么多,享元模式精髓也就是达到对象的共享,达到共享的话就须要抽出一部分东西达到类似。因此这又区分了内在状态和外在状态。内在状态不随环境变化而变化,属于可共享的。而外在状态随着环境改变而改变,因此不能共享的。在.Net开发中,咱们常用到的额String类型的实现就采用了享元模式的设计。在string中具备相同字符序列的String对象不会重复建立。具体细节想要研究的能够自行查询资料。在咱们使用设计模式的时候有一些点仍是须要屡次强调及注意的。基于原则设计。视状况采用设计模式。不要为了使用设计模式而去使用设计模式。一切都是为了重用代码、让代码更容易被他人理解、保证代码可靠性。
勇敢的面对不必定成功,但你不面对就必定不成功。
欢迎你们扫描下方二维码,和我一块儿踏上设计模式的闯关之路吧!