设计模式(11) 享元模式(FLYWEIGHT)(一)

2014-11-24 02:50:19 · 作者: · 浏览: 3
问题关注: 如果让我们设计一款文字编辑器,面向对象的设计方式肯定是首选。 一种可能的设计方式是,将文档中的每个字符,每行,每列都认为是一个对象,提高程序的灵活性的同时,可以想象,将会耗费大量内存。 享元模式,就是为了应对这种情况――共享对象,细粒度处理而无需高昂的代价。

意图: 运用共享技术,有效地支持大量细粒度的对象。
动机: 面向对象技术极大地提高了软件开发过程中的每个环节的效率,但是如果过于简单地使用它,代价也是极大的。 以在引言里提到的文档编辑器的设计为例。 常规设计:用对象来表示文档中的每个字符,每一行,每一列 优点:极大提高应用程序的灵活性。 缺点:极高的内存花费和运行开销。 如图: \ vcq9o7o8YnI+Cjx1bD4KPGxpPs6q19bEuLHt1tC1xMO/uPbX1sS4tLS9qNK7uPZmbHl3ZWlnaHSjrMO/uPZmbHl3ZWlnaHS05rSi0ru49tfWt/u0+sLro6y1q8v81NrOxLW11tC1xM671sO6zcXFsOa35yYjMjY2ODQ7v8nS1NTa19a3+7P2z9bKsdPJ1f3OxMXFsObL47eous3KudPDtcQmIzI2Njg0O8q9u6/D/MHuvva2qKGj0vK0y6Os19a3+7T6wuvKx8Tasr/XtMyso6y2+Mbky/u1xNDFz6LU8srHzeKyv9e0zKyhozxsaT7C37ytyc+jrM7EtbXW0LXEy/nT0NfWt/vDv7TOs/bP1ra809DSu7j2ttTP89PrxuS21NOmoaM8bGk+zu/A7cnPo6zX1sS4se3W0LXEw7+49tfWt/u5ss/t0ru49mZseXdlaWdodKOsy/nS1M2s0ru49tfWt/uz9s/WyrGjrNa4z/LNrNK7uPbKtcD9o6zV4rj2yrXA/c6709pmbHl3ZWlnaHS21M/ztcS5ss/ts9jW0KGjPGxpPsjnz8LNvMv5yr61xMTH0fmjrLHtyr7X1sS4tcRmbHl3ZWlnaHTWu7TmtKLP4NOmtcTX1rf7tPrC66OssqKyu7nY0MTOu9bDus3X1szltcjSu9CpzeKyv9DFz6KhozxsaT6x2NDr0qq1xM3isr/Qxc+io6zTyXJvd7bUz/OjrNTau+bWxsqxo6zM4bmpuPjX1sS7Zmx5d2VpZ2h0oaMKICAgIMjnz8LNvMv5yr6jugogICAgwt+8rcnPo7oKICAgIDxpbWcgc3JjPQ=="https://www.cppentry.com/upload_files/article/76/1_cdtr6__.png" alt="\"> \ 物理上: \ \ 结构: \ \

适用性: Flyweight模式的使用场景要求比较严格。 其有效性很大程度上取决于如何使用它以及在何处使用它。 当一下情况“都成立”时可以使用Flyweight模式:
  • 一个应用程序使用了大量的对象
  • 完全由于使用大量的对性爱那个,造成很大的存储开销
  • 对象的大多数状态都可变为外部状态
  • 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
  • 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的镀锡i昂,标识测试将返回真值 结构: \\ 下面的对象图说明了如何共享flyweight \\

    参与者:
    • Flyweight(Glyph):描述了一个接口,通过这个接口flyweight可以接受并作用于外部状态
    • ConcreteFlyweight(Character):实现Flyweight接口,并为内部状态增加存储空间
    • UnsharedConcreteFlyweight(Row, Column):并非所有的Flyweight子类都需要被共享。在Flyweight对象结构的某些层次中,UnsharedConcreteFlyweight对象通常将ConreteFlyweight作为字节带你,提供给它们外部信息。
    • FlyweightFactory:创建并管理flyweight对象;确保合理地共享flyweight,当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建爱你一个(如果不存在的话)。 协作:
      • flyweight执行时,所需要的状态必定是内部的或外部的。
      • 用户不应直接对ConcreteFlyweight类进行实例化,而只能从FlyweightFactory对象得到ConcreteFlyweight对象,这可以保证它们适当地进行共享。 效果: 节省内存,因素如下:
        • 共享,使得实例总数减少
        • 对象内部状态的平均数目减少
        • 外部状态是计算得到时更提高效率,当外部状态主要是计算出来的时,节约量打到最大 所以,Flyweight模式用两种方法节省内存:
          • 用共享减少内部状态的消耗
          • 用计算时间换取对外部状态的存储 实现: 实现Flyweight模式时,注意一下几点:
            • 处理外部状态
              • 如果不同种类的外部状态和共享前对象的数目相同的话,删除外部状态不会降低存储消耗
              • 理想情况,外部状态由一个单独的对象计算得到,且该结构的存储要求非常小
              • 在文档编辑器例子中,可以用一个单独的结构存储排版布局信息,而不是存储每一个字符对象的字体和类型信息
              • 管理共享对象
                • 用户不可以对共享对象进行直接实例化,因此FlyweightFactory可以帮助用户查找某个特定的Flyweight对象。

                  代码示例: 以上文提到的文档编辑器为例,重点讨论字体属性。 类设定: Glyph类:为Flyweight的图形对象定义的基类,属于Composite类(见组合模式Composite),有图形化属性,并可以绘制自己。
                  class Glyph {
                  public:
                      virtual ~Glyph();
                      virtual void Draw(Window*, GlyphContext&);
                  
                      virtual void SetFont(Font*, GlyphContext&);
                      virtual Font* GetFont(GlyphContext&);
                      virtual void First(GlyphContext&);
                      virtual void Next(GlyphContext&);
                      virtual bool IsDone(GlyphContext&);
                      virtual Glyph* Current(GlyphContext&);
                  
                      virtual void Insert(Glyph*, GlyphContext&);
                      virtual void Remove(GlyphContext&);
                  protected:
                      Glyph();
                  };
                  Character的子类存储一个字符代码:
                  class Character : public Glyph {
                  public:
                      Character(char);
                      virtual void Draw(Window*, GlyphContext&);
                  private:
                      char _charcode;
                  };
                  GlyphContext类 作用:避免给每个Glyph的字体属性都分配空间,可