爱上soso 发表于 2013-8-28 16:29

也谈一下“享元模式”

2本篇我们将会讲述结构性模式中的另外一个非常有用的模式-享元模式,享元模式的特点是,复用我们内存中已存在的对象,降低系统创建对象实例的性能消耗。在.NET下的值类型和引用类型的内存分配机制,我这里就不做详细的讲解了,包括引用类型与值类型之间的装箱和拆箱的操作,这个具体   
的可以参考园子里面的关于这方面的文章的讨论。   
    我们来给出个简单的享元模式的应用前后的对比图,大概我们就知道享元模式的重要作用了。   
    我们这里以绘制一个有样式的字体来说明吧,有的时候我们想绘制一个纯色的文字,比如红色,那么我们可能需要创建很多的实例,通常来说,这些   
实例的差别不大,这个时候,我们可以考虑复用其中创建的某个实例,而不用去new这么多相同的对象,来完成这样的工作。我们下面以这个例子来说   
明,使用享元模式的前后对比的情况。   
    使用享元模式前:   
    http://www.apkbus.com/data/attachment/forum/201301/24/115926apfxpzmzv7ksbf21.jpg      
    使用享元模式后:   
    http://www.apkbus.com/data/attachment/forum/201301/24/115927ijaxl2lljlwreu4q.jpg      
    通过上图我们可以大概的看出享元模式的目的是什么,本篇将会从以下几点出发,讲述享元模式的应用。   
    1、享元模式的特点和场景。   
    2、享元模式的经典实现。   
    3、享元模式的其他方案。   
    4、享元模式小结。   
下面我们来看下享元模式的类图吧:   
http://www.apkbus.com/data/attachment/forum/201301/24/115928t8v8bi5b7babovbv.jpg   
       a、上篇回顾。   
       b、摘要。   
       c、本文大纲。   
       d、享元模式的特点及使用场景。   
       e、享元模式的经典实现。   
       f、享元模式的其他方案。   
       g、享元模式使用总结。   
       h、系列进度。   
       i、下篇预告。   
      享元模式的意图是通过共享有效支持大量细粒度的对象,来提供应用程序的性能,节省系统中重复创建对象实例的性能消耗,这个怎么理解呢?其实就是以下几点的含义:   
1、当我们系统中某个对象类型的实例较多的情况。   
2、并且要求这些实例进行分类后,发现真正有区别的分类很少的情况。   
      例如我们的生活中很多的场景,我们在使用拼音输入的法的时候,如果说我们每个字都是new一个对象实例的操作的话,那么内存中的实例就太可   
怕,这个时候,我们是不是可以考虑将这些重复的字体在内存中只是创建一次,而是通过复用对象的形式,来组织一些可能有多个字符重复的内容呢?   
也许这是一个不错的主意,我们来看看这个示例的过程吧。   
http://www.apkbus.com/data/attachment/forum/201301/24/115929a8g6zljg2gpd1nzn.jpg      
         1、当我们发现某个类型的对象有大量的实例时,我们是否可以对这些实例进行分类,经过分类后,我们发现只有很少的类别的情况下。   
         2、我们发现通过使用享元模式后能够提高系统的性能和不会带来更多的复杂度时。   
      享元模式一般是给出本地内存资源节省的一个方案,并不适合互联网上的分布式应用的情况,不过享元模式对于排他性的要求资源的控制,是个不   
错的选择的。   
      我们下面来根据上面的我们对输入法中的字体来进行分析,给出相关的示例代码:   
      字体类型的基类:   
    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   
    {   
      privateDictionary<string, FontBase> fonts = new Dictionary<string, FontBase>();   
      publicFontBase Create(string name)   
      {   
            FontBase fontBase = fonts;   
            if (fontBase != null)   
                return fontBase;   
            fontBase = (FontBase)Activator.CreateInstance(Type.GetType(name));   
            return fontBase;   
      }   
    }   
通过上面实例的讲解我们知道,我们通过缓存对象类型的形式来控制对象实例的创建过程,经典的模式中没有体现共享的状态,比如说我们在外部可能对于   
享元对象来说是不共享的,内部是共享的。下面我们来看看享元模式的变种吧。   
            对于上面的经典方案带来的问题,可能我们需要更好的考虑,我们如何应对多种对象类型,我们如何管理并共享这些对象实例,这些都是我们需要考虑的问   
题,经过上面的思考,我们这里可以参考我们平时开发的ORM中的连接池的思路,我们这里对享元模式提供-对象池的技术。   
            我们在配置文件中控制对象池中的某个类型对象实例的数量,对象的生命周期的时间,默认初始化多少个对象实例,以提前准备,为后续的使用提供服务。   
            我们这里可以设计出这个专门的对象池,我们可以提供如下的功能:   
            1、根据对象类型动态的创建对象实例。   
            2、根据对象池中的配置,在对象池中找到空闲的实体提供给程序调用,减少创建对象的次数。   
            3、我们需要设计每个类型的缓冲池,通过把对象进行缓存,提供性能。如果对象池中的对象长期不会调用,那么我们会提供一个销毁对象的机制。   
我们来看看对象池的设计结构吧:   
http://www.apkbus.com/data/attachment/forum/201301/24/115930utdwutuzecy2f6o2.jpg      
通过上面的几个组件,来协调完成对象池的工作。   
这里给出相关的示例代码:   
我们先给出配置文件配置缓冲池的配置信息:   
   
?   
1   
2   
3   
4   
5   
6   
7   
8   
9   
10   
11   
12   
13   
14   
15   
16   
17   
页: [1]
查看完整版本: 也谈一下“享元模式”