享元模式 X 资源共享 X 项目多也别傻做

本文介绍了享元模式的概念及其在资源节省方面的应用,通过C++代码展示了如何利用享元模式实现网站分类,如blog、产品展示等,减少重复对象的创建,提高效率。享元模式通过内部和外部状态区分对象,有效减少了细粒度对象的实例数量。

享元模式(Flyweight),运用共享技术有效地支持大量细粒度的对象[DP]。

  1. #include <vector>
  2. #include <iostream>
  3. using namespace std;
  4. class Flyweight
  5. {
  6. public:
  7.     virtual void Operation(int extrinsicstate)=0;
  8. };
  9. class ConcreteFlyweight : public Flyweight
  10. {
  11. public:
  12.     virtual void Operation(int extrinsicstate)
  13.     {
  14.         cout<<"ConcreteFlyweight"<<endl;
  15.     }
  16. };
  17. //用来收容那些不需要共享的对象
  18. class UnsharedConcreteFlyweight : public Flyweight
  19. {
  20. public:
  21.     virtual void Operation(int extrinsicstate)
  22.     {
  23.         cout<<"UnsharedConcreteFlyweight"<<endl;
  24.     }
  25. };
  26. //一个享元工厂,用来创建并管理Flyweight对象。主要用来确保合理地共享Flyweight。
  27. //当用户请求一个Flyweight时,Flyweight对象提供一个已创建的实例或者创建一个(如果不存在的话)。
  28. class FlyweightFactory
  29. //本类和Flyweight是聚合关系,空心菱形加实线实心箭头,指向Flyweight类
  30. //Flyweight类对象作为其私有成员
  31. {
  32. private:
  33.     vector<Flyweight*> vFlyweight;
  34. public:
  35.     FlyweightFactory()
  36.     {
  37.         //按照某种方式构造Flyweight对象
  38.         vFlyweight.push_back(new ConcreteFlyweight());
  39.         vFlyweight.push_back(new ConcreteFlyweight());
  40.         vFlyweight.push_back(new ConcreteFlyweight());
  41.     }
  42.     Flyweight* GetFlyweight(/*参数*/)
  43.     {
  44.         //按照参数找到某个对象,并返回
  45.         return vFlyweight[0];
  46.     }
  47. };
  48. //客户端代码
  49. //Client和FlyweightFactory是关联关系,实心箭头指向FlyweightFactory
  50. //Client和ConcreteFlyweight、UnsharedConcreteFlyweight都是关联关系
  51. void main()
  52. {
  53.     //代码外部状态
  54.     int extrinsicstate = 32;
  55.     FlyweightFactory* f = new FlyweightFactory();
  56.     
  57.     //获取一个对象
  58.     Flyweight* fx = f->GetFlyweight();
  59.     fx->Operation(--extrinsicstate);
  60.     fx = f->GetFlyweight();
  61.     fx->Operation(--extrinsicstate);
  62.     UnsharedConcreteFlyweight* uf = new UnsharedConcreteFlyweight();
  63.     uf->Operation(--extrinsicstate);
  64. };

下面看一个具体的应用实例:如果有6个网站,分别用于blog、产品展示等等,我们没必要创建6个网站对象(如果不用享元的话,就需要6个Website类对象):看看代码是如何通过享元模式实现资源的节约的吧!

由于书上给出的例子是C#代码,我用C++改写之,没有使用Hashtable而用vector代替,所以不能编译运行下面的代码,表达一下意思即可。

 

  1. #include <string>
  2. #include <iostream>
  3. using namespace std;
  4. class Flyweight
  5. {
  6.     
  7. };
  8. class Website
  9. {
  10. public:
  11.     virtual void use() = 0;
  12. };
  13. class ConcreteWebsite : public Website
  14. {
  15. private:
  16.     string name;
  17. public:
  18.     ConcreteWebsite(string name) 
  19.     {
  20.         this->name = name;
  21.     }
  22.     void use()
  23.     {
  24.         cout<<"网站分类:"<<name<<endl;  
  25.     }
  26. };
  27. class WebsiteFactory
  28. {
  29. private:
  30.     vector<Flyweight*> vFlyweight;
  31. public:
  32.     //按照key查找website
  33.     Website* GetWebsiteCategory(string key)
  34.     {
  35.         //判断这个类型的网站对象是否存在,如果存在则直接返回
  36.         return vFlyweight[key];
  37.         //否则创建一个新的实例对象
  38.     }
  39.     int getWebsiteCount()
  40.     {
  41.         return vFlyweight.size();
  42.     }
  43. };
  44. //客户端代码
  45. void main()
  46. {
  47.     WebsiteFactory * f = new WebsiteFactory();
  48.     
  49.     //虽然使用了3次产品展示网站
  50.     Website* fx = f->GetWebsiteCategory("产品展示");
  51.     fx->use();
  52.     
  53.     fx = f->GetWebsiteCategory("产品展示");
  54.     fx->use();
  55.     
  56.     fx = f->GetWebsiteCategory("产品展示");
  57.     fx->use();
  58.     
  59.     //使用了两次blog网站
  60.     Website* f1 = f->GetWebsiteCategory("blog");
  61.     f1->use();
  62.     
  63.     f1 = f->GetWebsiteCategory("blog");
  64.     f1->use();
  65.     
  66.     f1 = f->GetWebsiteCategory("blog");
  67.     f1->use();
  68.     
  69.     //统计实例的个数,仍然是2个
  70.     cout<<f->getWebsiteCount();
  71. };

    也就是说,不管建几个网站,只要是“产品展示”,它们的代码都是一样的;blog网站也类似。(可想而知,它们公用一个数据库,当不同的用户以不同的身份登录时,返回数据库中的不同数据即可)

    享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类的数量。如果能把那些参数[1]移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。

    对于Flyweight执行时的状态,有内部的也有外部的:内部的存储于ConcreteFlyweight中,外部对象则由客户端对象存储或计算,在调用Flyweight对象的操作时,再将状态传递给ConcreteFlyweight。

    为了体现“不同对象返回不同数据”,看下面重载的客户端代码:

  1. void main()
  2. {
  3.     WebsiteFactory* f =new WebsiteFactory();
  4.     Website* fx = f->GetWebsiteCategory("产品展示");
  5.     fx->use(new User("小菜"));
  6.     //类似上面的代码,可以创建不同的用户,作为use函数的参数
  7. };

 

[1] 在示例中,就是指的new User("sombody")这个参数啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值