一雨田的专栏

伟人将复杂的事情变简单,小人将简单的事情变复杂

用户操作
[即时聊天] [发私信] [加为好友]
一雨田ID:dylgsy
91674次访问,排名1090,好友2人,关注者13人。
一雨田
dylgsy的文章
原创 41 篇
翻译 1 篇
转载 6 篇
评论 292 篇
最近评论
heray818:我的邮箱是:heray818@126.com
heray818:你好 能否也传我一份 谢谢了啊
救援隊募集:アダルトエロ不倫
モテ度審査員:童貞セフレナンパ
temp:很好
文章分类
收藏
    相册
    好友Blog
    圈内朋友
    sankt的专栏
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 设计模式简单代码之Flyweight模式收藏

    新一篇: 个人的学习曲线模型(UML) | 旧一篇: 身体器官工作时间表,要注意作息!!

    欢迎转载,请注明出处。

    [Flyweight模式]

     
    官方描述:

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

    适用性
     1、一个应用程序使用了大量的对象。
     2、完全由于使用大量的对象,造成很大的存储开销。
     3、对象的大多数状态都可变为外部状态。
     4、如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
     5、应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。


    我的描述:

     在开始设计类的时候,很自然的根据现实情况把某些属性作为类的一部分,例如设计一个图书的管理系统,每本书都有出版社、编号、作者、价钱等的属性,所以这个书的类可以这样设计:

    class Book
    {
    public:
     string GetPublish() {return m_publishCompany;}
     string GetWriter()  {return m_writer;}
     int GetBookID()  {return m_bookID;}
     int GetPrice()  {return m_price;}
     string GetName()    {return m_name;}

     void SetPublish(string &s) {m_publishCompany = s;}
     void SetWriter(string &s) {m_writer = s;}
     void SetBookID(int id)  {m_bookID = id;}
     void SetPrice(int price) {m_price = price;}
     void SetName(string &s)  {m_name = s;}

    private:
     string m_publishCompany; // 出版社
     string m_writer;   // 作者
     int m_bookID;    // 书籍编号
     int m_price;    // 价钱
     string m_name;    // 书名
    };

     这非常自然。但是随着系统的开发和试运行,这种设计就表现出一些不足的地方了,例如一般图书会非常多,成千上万本,在这些书中可能会有相同的出版社或者相同的作者,那对每本书来说就会重复了,也就是浪费了一些重复的空间。
    如果每本书都耗费一些空间,那整个软件系统所耗费的空间是不可想象的。所以,我们就要想办法来解决这个问题。
     高明的面向对象设计者就想出了这个办法,把一些相同的属性(把它叫做“享元”)提取出来,并用一个表来管理(池),这就是Flyweight模式的思想所在。好了,我们现在来看看示意图:

     


     

     
     这里的ConcreteFlyweight就是需要共享的属性(享元),例如上面的出版社和作者,这里的UnsharedConcreteFlyweight就是
    不用共享的属性(书籍编号和价钱)。

        想象一下系统里面Book类的使用:
     1、先看看不用共享模式:
     
     Book book1, book2, book3;
     book1.SetPublish("机械工业出版社");
     book1.SetWriter("候捷");
     book1.SetBookID(0000);
     book1.SetPrice(20);
     book1.SetName("C++好野");

     book2.SetPublish("人民邮电出版社");
     book2.SetWriter("候捷");
     book2.SetBookID(0001);
     book2.SetPrice(30);
     book2.SetName("C++是好劲");
     
     book3.SetPublish("机械工业出版社");
     book3.SetWriter("一雨田");
     book3.SetBookID(0002);
     book3.SetPrice(50);
     book3.SetName("C++无得顶,我是铁头功..."); 
     
     这里有两个“机械工业出版社”和两个“候捷”,重复了。如果使用共享模式的话,这里的浪费就可以避免了。
     别看这里只有两个,想象一下成千上万本书时的空间浪费...

     2、使用共享模式,把出版社和作者两个属性作为享元(Fly~~Weight)
     PublishFlyweightFactory pff;
     WriterFlyweightFactory wff;
     Book book1, book2, book3;

     book1.SetPublish(pff.GetPublish("机械工业出版社")->GetName());
     book1.SetWriter(wff.GetWriter("候捷")->GetName());
     book1.SetBookID(0000);
     book1.SetPrice(20);
     book1.SetName("C++好野");

     book2.SetPublish(pff.GetPublish("人民邮电出版社")->GetName());
     book2.SetWriter(wff.GetWriter("候捷")->GetName());
     book2.SetBookID(0001);
     book2.SetPrice(30);
     book2.SetName("C++是好劲");

     book3.SetPublish(pff.GetPublish("机械工业出版社")->GetName());
     book3.SetWriter(wff.GetWriter("一雨田")->GetName());
     book3.SetBookID(0002);
     book3.SetPrice(50);
     book3.SetName("C++无得顶,我是铁头功...");

     为什么使用了PublishFlyweightFactory和WriterFlyweightFactory之后就可以节省空间了呢?

     奥妙就在于GetPublish和GetWriter的实现:
     
     PublishFlyweight* GetPublish(string key)
     {
      PublishFlyweight *p;
      mapPublish::iterator it;
      it = mapPublish.find(key);

      // 存在这个Writer
      if(it != mapPublish.end() )
       p = it;

      else
      {// 插入这个PublishFlyweight
       
       p = new PublishFlyweight(key);
       mapPublish[key] = p;
      }

      return p;
     }
     
     GetWriter的实现大同小异,这里就不列出来了,请看详细代码里的实现。 

    下面是完整的代码,可以在一个CPP文件里编译使用,由于使用CSDN提供的插入代码功能会使得整段拷贝有点问题,所以这里还是直接给出代码,并标注颜色,方便大家的拷贝:

    // Flyweight.cpp

    #pragma warning(disable: 4786)

    #include <iostream>
    #include <map>
    #include <string>
    using namespace std;


    class Book
    {
    public:
     string GetPublish() {return *m_publishCompany;}
     string GetWriter()  {return *m_writer;}
     int GetBookID()  {return m_bookID;}
     int GetPrice()  {return m_price;}
     string GetName()    {return m_name;}
     
     void SetPublish(string *s) {m_publishCompany = s;}
     void SetWriter(string *s) {m_writer = s;}
     void SetBookID(int id)  {m_bookID = id;}
     void SetPrice(int price) {m_price = price;}
     void SetName(string &s)  {m_name = s;}
     
    private:
     string *m_publishCompany; // 出版社
     string *m_writer;   // 作者
     int m_bookID;    // 书籍编号
     int m_price;    // 价钱
     string m_name;    // 书名
    };

    class PublishFlyweight
    {
    public:
     PublishFlyweight(string s)
     {
      m_name = s;
     }
     string GetName()
     {
      return m_name;
     }
     
    private:
     string m_name;
    };

    class PublishFlyweightFactory
    {
    public:
     PublishFlyweight* GetPublish(string key)
     {
      PublishFlyweight *p;
      map<string, PublishFlyweight*>::iterator it;
      it = mapPublish.find(key);
      
      // 存在这个出版社
      if(it != mapPublish.end() )
      {
       // 这里可能有点难懂,请查阅STL的帮助文档
       // 其实second就是指 map<string, PublishFlyweight*> 的 PublishFlyweight*
       p = (*it).second;
       cout << "已经有这个出版社: " << p->GetName() << " 你节省了" << strlen(p->GetName().c_str()) << "字节的空间" << endl;
      }
      
      else
      {// 插入这个PublishFlyweight
       
       p = new PublishFlyweight(key);
       mapPublish[key] = p;
      }
      
      return p;
     }
     
    private:
     map<string, PublishFlyweight*> mapPublish;
    };

    class WriterFlyweight
    {
    public:
     WriterFlyweight(string s)
     {
      m_name = s;
     }
     string GetName()
     {
      return m_name;
     }
     
    private:
     string m_name;
    };

    class WriterFlyweightFactory
    {
    public:
     WriterFlyweight* GetWriter(string key)
     {
      WriterFlyweight *p;
      map<string, WriterFlyweight*>::iterator it;
      it = mapWriter.find(key);
      
      // 存在这个Writer
      if(it != mapWriter.end() )
      {
       // 这里可能有点难懂,请查阅STL的帮助文档
       // 其实second就是指 map<string, WriterFlyweight*> 的 WriterFlyweight*
       p = (*it).second;
       cout << "已经有这个作者名字: " << p->GetName() << " 你节省了" << strlen(p->GetName().c_str()) << "字节的空间" << endl;
      }
      
      else
      {// 插入这个PublishFlyweight
       
       p = new WriterFlyweight(key);
       mapWriter[key] = p;
      }
      
      return p;
     }
     
    private:
     map<string, WriterFlyweight*> mapWriter;
    };


    void ShowBookInfo(Book book)
    {
     cout << "书名:" << book.GetName() << endl;
     cout << "编号:" << book.GetBookID() << endl;
     cout << "价钱:" << book.GetPrice() << endl;
     cout << "出版:" << book.GetPublish() << endl;
     cout << "作者:" << book.GetWriter() << endl;
     cout << endl;
    }

    void main()
    {
     PublishFlyweightFactory pff;
     WriterFlyweightFactory wff;
     Book book1, book2, book3;
     
     book1.SetPublish( &(pff.GetPublish("机械工业出版社")->GetName()) );
     book1.SetWriter( &(wff.GetWriter("候捷")->GetName()) );
     book1.SetBookID(0000);
     book1.SetPrice(20);
     book1.SetName(string("<<C++好野>>"));
     
     ShowBookInfo(book1);
     
     book2.SetPublish( &(pff.GetPublish("人民邮电出版社")->GetName()) );
     book2.SetWriter( &(wff.GetWriter("候捷")->GetName()) );
     book2.SetBookID(0001);
     book2.SetPrice(30);
     book2.SetName(string("<<C++是好劲>>"));
     
     ShowBookInfo(book2);
     
     book3.SetPublish( &(pff.GetPublish("机械工业出版社")->GetName()) );
     book3.SetWriter( &(wff.GetWriter("一雨田")->GetName()) );
     book3.SetBookID(0002);
     book3.SetPrice(50);
     book3.SetName(string("<<C++无得顶,我是铁头功...>>"));
     
     ShowBookInfo(book3);
    }

    好了,如果你能看到这里,希望能帮助你把Flyweight模式理解了,但最好还是动手把代码拷贝到VC 里,编译运行一下,你可以看到Flyweight模式帮你节省了多少空间。谢谢!

    发表于 @ 2006年08月10日 12:30:00|评论(loading...)|编辑

    新一篇: 个人的学习曲线模型(UML) | 旧一篇: 身体器官工作时间表,要注意作息!!

    评论

    #feng 发表于2006-08-11 13:53:00  IP: 219.136.190.*
    楼主终于又写设计模式了,呵呵,非常好!
    #zhou 发表于2006-08-11 14:40:00  IP: 211.154.11.*
    好人
    #展松 发表于2006-08-11 22:09:00  IP: 218.19.183.*
    好东西,要收藏!!
    #shan 发表于2006-08-12 00:09:00  IP: 221.204.11.*
    感觉 vc 6.0 不则么好用啊
    #晕死 发表于2006-08-14 09:46:00  IP: 219.136.79.*
    模式理解了,可是例子无论如何看不明白空间省在哪了

    book依然有m_publishName 和m_write,依然把“某某某出版社”
    和“某某某”作者一次不剩,一点不省的存在了每一个book对象中。

    如果真要省空间,flyweight应该用一个自动增长的整数作为key,把整数返回来让book保存,需要get的时候,用key检索并返回string
    #一雨田 发表于2006-08-14 11:37:00  IP: 202.105.42.*
    噢,确实是我的疏忽,谢谢“晕死”兄提出。
    程序已经修改过来了,修改的方法是Book类中的 m_publishCompany和m_writer改成了指针,这样它们就指向flyweight 池中已有的对象,而不会新复制一个对象了,这样才真正达到了节省空间的目的。
    #classpatterns 发表于2007-04-05 17:08:14  IP: 60.209.186.*
    赫赫 其实price也可以啊
    也就1 ~ 500之间

    其实超过300的偶也没见过 哈..

    #qmroom 发表于2008-08-27 08:52:52  IP: 221.224.118.*
    为什么出版社和作者显示不了?在程序运行时
    我用vc2005调试时竟然死机,晕啊~~~
    用vc6调试时,在map里找不到"机械工业出版社"。返回指针指向的值为NULL
    楼主看看这是什么原因啊?
    #qmroom 发表于2008-08-27 09:22:45  IP: 221.224.118.*
    //我修改了一下,可以显示了
    /*
    来源:一雨田Blog
    问题:出版社和作者显示不了
    修改:qmroom
    */


    // Flyweight.cpp

    #pragma warning(disable: 4786)

    #include <iostream>
    #include <map>
    #include <string>
    #include <stdlib.h>
    using namespace std;

    typedef char CHAR;
    typedef CHAR *LPSTR;
    typedef const CHAR *LPCSTR;

    class Book
    {
    public:
    string GetPublish() {return *m_publishCompany;}
    string GetWriter() {return *m_writer;}
    int GetBookID() {return m_bookID;}
    int GetPrice() {return m_price;}
    string GetName() {return m_name;}

    void SetPublish(string *s) {m_publishCompany = s;}
    void SetWriter(string *s) {m_writer = s;}
    void SetBookID(int id) {m_bookID = id;}
    void SetPrice(int price) {m_price = price;}
    void SetName(LPCSTR s) {m_name = s;}

    private:
    string *m_publishCompany; // 出版社
    string *m_writer; // 作者
    int m_bookID; // 书籍编号
    int m_price; // 价钱
    string m_name; // 书名
    };

    class PublishFlyweight
    {
    public:
    PublishFlyweight(string s)
    {
    m_name = new string(s);
    }
    virtual ~PublishFlyweight()
    {
    delete(m_name);
    }
    string *GetName()
    {
    return m_name;
    }

    private:
    string *m_name;
    };

    class PublishFlyweightFactory
    {
    public:
    PublishF
    #qmroom 发表于2008-08-27 09:24:16  IP: 221.224.118.*
    #pragma warning(disable: 4786) 可以去掉
    #qmroom 发表于2008-08-27 09:26:28  IP: 221.224.118.*

    class PublishFlyweightFactory
    {
    public:
    PublishFlyweight* GetPublish(string key)
    {
    PublishFlyweight *p;
    map<string, PublishFlyweight*>::iterator it;
    it = mapPublish.find(key);

    // 存在这个出版社
    if(it != mapPublish.end() )
    {
    // 这里可能有点难懂,请查阅STL的帮助文档
    // 其实second就是指 map<string, PublishFlyweight*> 的 PublishFlyweight*
    p = (*it).second;
    cout << "已经有这个出版社: " << *(p->GetName()) << " 你节省了" << strlen((*(p->GetName())).c_str()) << "字节的空间" << endl;
    }
    else
    {
    // 插入这个PublishFlyweight
    p = new PublishFlyweight(key);
    mapPublish[key] = p;
    }

    return p;
    }

    private:
    map<string, PublishFlyweight*> mapPublish;
    };

    class WriterFlyweight
    {
    public:
    WriterFlyweight(string s)
    {
    m_name = new string(s);
    }
    virtual ~WriterFlyweight()
    {
    delete(m_name);
    }
    string *GetName()
    {
    return m_name;
    }

    private:
    string *m_name;
    };
    #qmroom 发表于2008-08-27 09:26:58  IP: 221.224.118.*

    class WriterFlyweightFactory
    {
    public:
    WriterFlyweight* GetWriter(string key)
    {
    WriterFlyweight *p;
    map<string, WriterFlyweight*>::iterator it;
    it = mapWriter.find(key);

    // 存在这个Writer
    if(it != mapWriter.end() )
    {
    // 这里可能有点难懂,请查阅STL的帮助文档
    // 其实second就是指 map<string, WriterFlyweight*> 的 WriterFlyweight*
    p = (*it).second;
    cout << "已经有这个作者名字: " << *(p->GetName()) << " 你节省了" << strlen((*(p->GetName())).c_str()) << "字节的空间" << endl;
    }
    else
    {
    // 插入这个PublishFlyweight
    p = new WriterFlyweight(key);
    mapWriter[key] = p;
    }

    return p;
    }

    private:
    map<string, WriterFlyweight*> mapWriter;
    };


    void ShowBookInfo(Book book)
    {
    cout << "书名:" << book.GetName() << endl;
    cout << "编号:" << book.GetBookID() << endl;
    cout << "价钱:" << book.GetPrice() << endl;
    cout << "出版:" << book.GetPublish() << endl;
    cout << "作者:" << book.GetWriter() << endl;
    cout << endl;
    }
    #qmroom 发表于2008-08-27 09:27:20  IP: 221.224.118.*
    void main()
    {
    PublishFlyweightFactory pff;
    WriterFlyweightFactory wff;
    Book book1, book2, book3;

    book1.SetPublish( pff.GetPublish("机械工业出版社")->GetName() );
    book1.SetWriter( wff.GetWriter("候捷")->GetName() );
    book1.SetBookID(0000);
    book1.SetPrice(20);
    book1.SetName(("<<C++好野>>"));

    ShowBookInfo(book1);

    book2.SetPublish( pff.GetPublish("人民邮电出版社")->GetName() );
    book2.SetWriter( wff.GetWriter("候捷")->GetName() );
    book2.SetBookID(0001);
    book2.SetPrice(30);
    book2.SetName(("<<C++是好劲>>"));

    ShowBookInfo(book2);

    book3.SetPublish( pff.GetPublish("机械工业出版社")->GetName() );
    book3.SetWriter( wff.GetWriter("一雨田")->GetName() );
    book3.SetBookID(0002);
    book3.SetPrice(50);
    book3.SetName(("<<C++无得顶,我是铁头功...>>"));

    ShowBookInfo(book3);

    system("pause");
    }
    #qmroom 发表于2008-08-27 09:45:54  IP: 221.224.118.*
    详细分析见:http://blog.csdn.net/qmroom/archive/2008/08/27/2836128.aspx
    #qmroom 发表于2008-08-27 09:47:21  IP: 221.224.118.*
    详细分析见:http://blog.csdn.net/qmroom/archive/2008/08/27/2836128.aspx
    #qmroom 发表于2008-08-27 09:47:24  IP: 221.224.118.*
    详细分析见:http://blog.csdn.net/qmroom/archive/2008/08/27/2836128.aspx
    #qmroom 发表于2008-08-27 09:47:26  IP: 221.224.118.*
    详细分析见:http://blog.csdn.net/qmroom/archive/2008/08/27/2836128.aspx
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © 一雨田