设计模式 笔记 享元模式 Flyweight





//---------------------------15/04/20----------------------------



//Flyweight 享元模式------对象结构型模式

/*

    1:意图:

        运用共享技术有效地支持大量细粒度的对象。

    2:动机:

    3:适用性:

        以下条件都成立时才能使用。

        1>一个应用程序使用了大量的对象。

        2>完全由于使用大量的对象,造成很大的存储开销。

        3>对象的大多数状态都可变为外部状态。

        4>如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。

        5>应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的

          对象,标识测试将返回真值。

    4:结构:

        FlyweightFactory:

        flyweights--------------------------------->Flyweight:

        GetFlyweight(key)                           Operation(extrinsicState)

        { if(flyweight[key] exists)                     |

            return exisiting flyweight;                 |

          else                                          |

            create new flyweight;                       |

            add it to pool of flyweights;               |

            return the new flyweight;                   |

        }    |                               ------------------------

             |                               |                      |

             |                |---->ConcreteFlyweight        |--->UnsharedConcreteFlyweight

            Client------------|     Operation(extrinsicState)|    Operation(extrinsicState)

                              |     instrinsicState          |    allState

                              --------------------------------

    5:参与者:

        1>Flyweight

            描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。

        2>ConcreteFlyweight

            实现Flyweight接口,并为内部状态(如果有的话)增加存储空间。ConcreteFlyweight对象必须是

            可共享的。它存储的内部状态必须和场景无关。

        3>UnsharedConcreteFlyweight

            并非所有的Flyweight子类都需要被共享。Flyweight接口使得共享成为可能,但是它并不强制共享。

            UnsharedConcreteFlyweight对象通常把ConcreteFlyweight对象作为子节点。

        4>FlyweightFactory

            1)创建并管理flyweight对象。

            2)确保合理地共享flyweight。拥有一个接口可以返回一个flyweight对象(如果不存在会创建一个)

        5>Client

            1)维持一个对flyweight的引用。

            2)计算或存储一个(或多个)flyweight的外部状态。

    6:协作:

        1>flyweight执行时所需的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象中;而

          外部对象则由Client对象存储或计算。当用户调用flyweight的操作时,只需要把状态传递给它。

          (就是operation的那个操作,可以传入一个状态,然后由ConcreteFlyweight对象实现操作)

        2>用户不应该直接对ConcreteFlyweight类进行实例化,而只能从FlyweightFactory对象得到

          ConcreteFlyweight对象。

          关于这点,可以直接隐藏掉ConcreteFlyweight的定义,只通过工厂返回基类指针。

    7:效果:

        1>这个模式使用时间来换空间(大量),因为参数传输,工厂查找,外部状态的计算都会产生运行时的开销。

        2>节省的空间由一下决定:

            1)因为共享而减少的 实例总数目。

            2)对象内部状态的 平均数目。

            3)外部状态时 计算的 还是存储的。

          总结起来:共享的Flyweight越多,节省越多。节省的量随着共享的状态(内部状态)的增多而增大。外部状态时

          计算的而非存储的。则能节省大量存储。

    8:实现:

        1>删除外部状态

            外部状态的数量和大小决定了Flyweight模式的可用性。如果外部状态很多而且存储要求高,那么删除

            外部状态就没有意义了。最理想的情况是:外部状态可以由一个单独的对象结构计算得到,且该结构的

            存储要求非常小。

        2>管理共享对象

            因为对象时共享的,所以用户不能直接对它进行实例化,通常FlyweightFactory可以帮助用户找到某个

            特定的Flyweight对象。FlyweightFactory通常采用关联存储(set map)帮助用户查找感兴趣的

            Flyweight对象。

    9:代码示例:                                                                             */


//abstract Flyweight:声明了Flyweight的接口

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();

};


//ConcreteFlyweight:这里只需要ascii码就够了

class Character : public Glyph

{

public:

    Character(char);

    virtual void Draw(Window*, GlyphContext&);

    

private:

    char _charcode;

};


//客户自己创建维护的 外部状态-字体

//由于是根据范围来确定字体,所以字体采取btree来存储,btree的最底层对应了相应的字体。

class GlyphContext

{

public:

    virtual ~GlyphContext();

    virtual void Next(int step = 1);

    virtual Font* GetFont();

    virtual void SetFont(Font*, int span = 1);

    

private:

    int _index;

    BTree* _fonts;

};


//工厂,可以返回具体的Flyweight对象

const int NCHARCODES = 128;


class GlyphFactory

{

public:

    GlyphFactory();

    virtual ~GlyphFactory();

    virtual Character* CreateCharacter(char);

    virtual Row* CreateRow();

    virtual Column* CreateColumn();

    

private:

    Character* _character[NCHARCODES];

};



posted @ 2015-04-21 09:06  boydfd  阅读(178)  评论(0编辑  收藏  举报