设计模式系列-享元模式

 

1、上篇回顾

      经过上篇的讲述,咱们知道装饰模式,特别适合对某个类型的对象,动态的增长新的职责,应用程序就像使用原来的对象同样使用对象新增的装饰html

后的功能,装 饰模式就好像是穿了一层层的外壳,这样的方式避免了经过继承来为类型添加新的职责的形式可取,经过继承的方式容易形成子类的膨java

胀,可是当装饰类太多的时 候,也是个难以维护的问题,至少是在装饰对象的时候,咱们可能须要多步操做来完成对象的装饰,这时候咱们能够同上面设计模式

提出的改进的方案,来完成自动配置装饰 模式,记录操做模式的状态,能够进行有效的回滚操做,以完成撤销操做。缓存

      咱们先来回顾下装饰模式的使用场景:架构

      一、当咱们须要为某个现有的对象,动态的增长一个新的功能或职责时,能够考虑使用装饰模式。分布式

      二、适应于某个对象的职责常常发生变化或者常常须要动态的增长职责,避免由于这种为了适应这样的变化,而增长继承子类扩展的方式,由于ide

这种方式为 形成,子类膨胀的速度过快,难以控制。函数

2、摘要

    本篇咱们将会讲述结构性模式中的另一个很是有用的模式-享元模式,享元模式的特色是,复用咱们内存中已存在的对象,下降系统建立对象实例性能

的性能消耗。在.NET下的值类型和引用类型的内存分配机制,我这里就不作详细的讲解了,包括引用类型与值类型之间的装箱和拆箱的操做,这个具体字体

的能够参考园子里面的关于这方面的文章的讨论。

    咱们来给出个简单的享元模式的应用先后的对比图,大概咱们就知道享元模式的重要做用了。

    咱们这里以绘制一个有样式的字体来讲明吧,有的时候咱们想绘制一个纯色的文字,好比红色,那么咱们可能须要建立不少的实例,一般来讲,这些

实例的差异不大,这个时候,咱们能够考虑复用其中建立的某个实例,而不用去new这么多相同的对象,来完成这样的工做。咱们下面以这个例子来讲

明,使用享元模式的先后对比的状况。

    使用享元模式前:

    p_w_picpath

    使用享元模式后:

    p_w_picpath

    经过上图咱们能够大概的看出享元模式的目的是什么,本篇将会从如下几点出发,讲述享元模式的应用。

    一、享元模式的特色和场景。

    二、享元模式的经典实现。

    三、享元模式的其余方案。

    四、享元模式小结。

下面咱们来看下享元模式的类图吧:

3、本文大纲

       a、上篇回顾。

       b、摘要。

       c、本文大纲。

       d、享元模式的特色及使用场景。

       e、享元模式的经典实现。

       f、享元模式的其余方案。

       g、享元模式使用总结。

       h、系列进度。

       i、下篇预告。

4、享元模式的特色及使用场景

      4.一、享元模式的特色

      享元模式的意图是经过共享有效支持大量细粒度的对象,来提供应用程序的性能,节省系统中重复建立对象实例的性能消耗,这个怎么理解呢?其实就是如下几点的含义:

一、当咱们系统中某个对象类型的实例较多的状况。

二、而且要求这些实例进行分类后,发现真正有区别的分类不多的状况。

      例如咱们的生活中不少的场景,咱们在使用拼音输入的法的时候,若是说咱们每一个字都是new一个对象实例的操做的话,那么内存中的实例就太可

怕,这个时候,咱们是否是能够考虑将这些重复的字体在内存中只是建立一次,而是经过复用对象的形式,来组织一些可能有多个字符重复的内容呢?

也许这是一个不错的主意,咱们来看看这个示例的过程吧。

p_w_picpath

      4.二、享元模式的使用场景

         一、当咱们发现某个类型的对象有大量的实例时,咱们是否能够对这些实例进行分类,通过分类后,咱们发现只有不多的类别的状况下。

         二、咱们发现经过使用享元模式后可以提升系统的性能和不会带来更多的复杂度时。

      享元模式通常是给出本地内存资源节省的一个方案,并不适合互联网上的分布式应用的状况,不过享元模式对于排他性的要求资源的控制,是个不

错的选择的。

5、享元模式的经典实现

      咱们下面来根据上面的咱们对输入法中的字体来进行分析,给出相关的示例代码:

      字体类型的基类:

    public class FontBase 
    { 
        private List<string> font = new List<string>();

        private string fontName; 
        public FontBase(string name) 
        { 
            this.fontName = name; 
        }

        public FontBase AddFont(string font) 
        { 
            this.font.Add(font); 
            return this; 
        } 
        public virtual string FontName 
        { 
            get 
            { 
                return this.fontName; 
            } 
        } 
    }

    具体的文字类型类:

    public class ChineseFont : FontBase 
    { 
        public ChineseFont() 
            : base("ChineseFont") 
        { 
            base.AddFont("ChineseFont"); 
        } 
    }

    public class EnglishFont : FontBase 
    { 
        public EnglishFont() 
            : base("EnglishFont") 
        { 
            base.AddFont("EnglishFont"); 
        } 
    }

具体的建立工厂类:

    public class FontFactory 
    { 
        private  Dictionary<string, FontBase> fonts = new Dictionary<string, FontBase>();

        public  FontBase Create(string name) 
        { 
            FontBase fontBase = fonts[name]; 
            if (fontBase != null) 
                return fontBase;

            fontBase = (FontBase)Activator.CreateInstance(Type.GetType(name));

            return fontBase; 
        } 
    }

经过上面实例的讲解咱们知道,咱们经过缓存对象类型的形式来控制对象实例的建立过程,经典的模式中没有体现共享的状态,好比说咱们在外部可能对于

享元对象来讲是不共享的,内部是共享的。下面咱们来看看享元模式的变种吧。

6、享元模式的其余方案

            对于上面的经典方案带来的问题,可能咱们须要更好的考虑,咱们如何应对多种对象类型,咱们如何管理并共享这些对象实例,这些都是咱们须要考虑的问

题,通过上面的思考,咱们这里能够参考咱们平时开发的ORM中的链接池的思路,咱们这里对享元模式提供-对象池的技术。

            咱们在配置文件中控制对象池中的某个类型对象实例的数量,对象的生命周期的时间,默认初始化多少个对象实例,以提早准备,为后续的使用提供服务。

            咱们这里能够设计出这个专门的对象池,咱们能够提供以下的功能:

            一、根据对象类型动态的建立对象实例。

            二、根据对象池中的配置,在对象池中找到空闲的实体提供给程序调用,减小建立对象的次数。

            三、咱们须要设计每一个类型的缓冲池,经过把对象进行缓存,×××能。若是对象池中的对象长期不会调用,那么咱们会提供一个销毁对象的机制。

咱们来看看对象池的设计结构吧:

p_w_picpath

经过上面的几个组件,来协调完成对象池的工做。

这里给出相关的示例代码:

咱们先给出配置文件配置缓冲池的配置信息:

 

<?xml version="1.0" encoding="utf-8" ?>
<Cache>
  <ObjectSection name="" type=""/>
  <ObjectCache>
    <object name="" type="" max="" timeout="" />
    <object name="" type="" max="" timeout="" />
    <object name="" type="" max="" timeout="" />
    <object name="" type="" max="" timeout="" />
    <object name="" type="" max="" timeout="" />
    <object name="" type="" max="" timeout="" />
    <object name="" type="" max="" timeout="" />
    <object name="" type="" max="" timeout="" />
    <object name="" type="" max="" timeout="" />
  </ObjectCache>
</Cache>

咱们来看看具体的工厂类:
     
     
              
     
     
    public class ObjectFactory
    {
        public static T Build<T>() where T:class,new()
        {
            return new T();
        }
    }
咱们来看看具体的缓存类:

     
     
              
     
     
    public class ObjectCache 
    {
        private static Dictionary<Type, object> cache =null;

        public static ObjectCache()
        {
            cache = new Dictionary<Type, object>();
        }

        public void Cache<T>(T item)
        {
            cache.Add(typeof(T),item);
        }

        public void GetObjectFromCache<T>( out T item)
        {
            if (cache[typeof(T)] != null)
                item = cache[typeof(T)];
        }
    }

7、享元模式使用总结

      享元模式的主旨意在经过共享对象节省整体资源,不过共享对象将致使资源访问上的一些问题,包括对象实例的销毁,还包括线程间的共享和线程

内的共享是不一样的,咱们知道,通常线程退出的时候,会自动释放线程内部的申请的资源,.NET会自动经过GC来回收,可是对于线程间共享的对象也

许不会自动回收,这些内容须要宿主进程来进行回收,固然可能这些咱们也能够经过对象池来完成这样的回收机制。  或者说也能够参考操做系统中的

队列的状况,经过回调函数来通知进行对象的回收等。咱们在对于项目中须要大量实例对象的建立工做的时候,咱们就考虑一下是否是须要享元模式的

应用了,但愿你们能在项目中找到合适的切入点,使用合适的模式来提升程序的适应性和健壮性。因为本人水平有限,不足或者错误之处,还请你们批

评指出。

8、系列进度

建立型

        一、系统架构技能之设计模式-单件模式

        二、系统架构技能之设计模式-工厂模式

        三、系统架构技能之设计模式-抽象工厂模式

        四、系统架构技能之设计模式-建立者模式

        五、系统架构技能之设计模式-原型模式

结构型

        一、系统架构技能之设计模式-组合模式

        二、系统架构技能之设计模式-外观模式

        三、系统架构技能之设计模式-适配器模式

        四、系统架构技能之设计模式-桥模式

        五、系统架构技能之设计模式-装饰模式

        六、系统架构技能之设计模式-享元模式

        七、系统架构技能之设计模式-代理模式

行为型

        一、系统架构技能之设计模式-命令模式

        二、系统架构技能之设计模式-观察者模式

        三、系统架构技能之设计模式-策略模式

        四、系统架构技能之设计模式-职责模式

        五、系统架构技能之设计模式-模板模式

        六、系统架构技能之设计模式-中介者模式

        七、系统架构技能之设计模式-解释器模式

9、下篇预告

        下篇咱们将开始介绍结构性模式中的-代理模式。代理模式就是为了将某些对象的复杂性隐藏起来,使咱们使用复杂对象的代理,就像使用简单对象同样,下篇我

们将会从几个方面讲解代理模式的应用,但愿你们多多提出不一样的已经和建议。

相关文章
相关标签/搜索