享元模式
享元模式定义
享元模式(Flyweight),运用享元技术有效支持大量细粒度的对象。
享元模式结构图
享元模式结构图如下所示:
图 01 享元模式结构图
享元模式套用代码
1 #include <iostream> 2 #include <string> 3 #include <map> 4 using namespace std; 5 6 class Flyweight 7 { 8 public: 9 virtual void operation(int)=0; 10 11 virtual ~Flyweight() 12 { 13 14 } 15 }; 16 17 class ConcreteFlyweight:public Flyweight 18 { 19 virtual void operation(int extrinsicState) 20 { 21 cout<<"具体FlyWeight: "<<extrinsicState<<endl; 22 } 23 24 virtual ~ConcreteFlyweight() 25 { 26 27 } 28 }; 29 30 class UnsharedConcreteFlyweight:public Flyweight 31 { 32 virtual void operation(int extrinsicState) 33 { 34 cout<<"不共享的具体FlyWeight: "<<extrinsicState<<endl; 35 } 36 37 virtual ~UnsharedConcreteFlyweight() 38 { 39 40 } 41 }; 42 43 class FlyweightFactory 44 { 45 private: 46 map<string,Flyweight*> flyweights; 47 public: 48 FlyweightFactory() 49 { 50 flyweights["X"]=new ConcreteFlyweight(); 51 flyweights["Y"]=new ConcreteFlyweight(); 52 flyweights["Z"]=new ConcreteFlyweight(); 53 } 54 55 Flyweight *getFlyweight(string key) 56 { 57 return (Flyweight *)flyweights[key]; 58 } 59 60 virtual ~FlyweightFactory() 61 { 62 map<string,Flyweight*>::iterator it = flyweights.begin(); 63 while(it != flyweights.end()) 64 { 65 delete (it->second); 66 it++; 67 // flyweights.erase(it++); 68 } 69 } 70 }; 71 72 73 void main() 74 { 75 int state=22; 76 FlyweightFactory *f=new FlyweightFactory(); 77 78 Flyweight *fx=f->getFlyweight("X"); 79 fx->operation(--state); 80 81 Flyweight *fy=f->getFlyweight("Y"); 82 fy->operation(--state); 83 84 Flyweight *fz=f->getFlyweight("Z"); 85 fz->operation(--state); 86 87 Flyweight *uf=new UnsharedConcreteFlyweight(); 88 uf->operation(--state); 89 90 delete f; 91 f = NULL; 92 93 delete uf; 94 uf = NULL; 95 }
享元模式特点
① FlyweightFactory根据客户需求返回早已生成好的对象,但一定要事先在构造函数中生成对象实例吗?实际上是不一定需要的,完全可以初始化时什么也不做,到需要时,再去判断对象是否为NULL来决定是否实例化。
② 为什么要有UnsharedConcreteFlyweight的存在?这是因为尽管我们大部分时间都需要共享对象来降低内存的损耗,但个别时候也有可能不需要共享的,那么此时的UnsharedConcreteFlyweight子类就有存在的必要了,它可以解决那些不需要共享对象的 问题。
③ 享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。也就是说,享元模式Flyweight执行时所需的状态是有内部的也可能有外部的,内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给它。
④ 如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用享元模式,还有就是对象的大多数状态可以外部状态,如果删除对象的 外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
⑤ C++中的string就是运用了Flyweight模式。
享元模式实例应用
享元模式实例应用类图
图 02 享元模式实例应用类图
享元模式实例应用代码
1 #include <iostream> 2 #include <list> 3 #include <string> 4 #include <map> 5 using namespace std; 6 7 8 // 用户类 9 class CUser 10 { 11 private: 12 string name; 13 public: 14 CUser(string name) 15 { 16 this->name = name; 17 } 18 19 string GetName() 20 { 21 return this->name; 22 } 23 }; 24 25 class CWebSite 26 { 27 public: 28 virtual void use(CUser* user) = 0; 29 30 virtual ~CWebSite() 31 { 32 33 } 34 }; 35 36 class CConcreteWebSite : public CWebSite 37 { 38 private: 39 string name; 40 public: 41 CConcreteWebSite(string name) 42 { 43 this->name = name; 44 } 45 46 virtual void use(CUser* user) 47 { 48 cout << "网站分类: " << name << " 用户: "<< user->GetName() << endl; 49 } 50 51 virtual ~CConcreteWebSite() 52 { 53 54 } 55 }; 56 57 class CWebSiteFactory 58 { 59 private: 60 map<string,CWebSite*> wf; 61 public: 62 63 CWebSite *GetWebSiteCategory(string key) 64 { 65 // 如果已经存在实例则返回,否则创建 66 if(wf.find(key)==wf.end()) 67 { 68 wf[key]=new CConcreteWebSite(key); 69 } 70 71 return wf[key]; 72 } 73 74 int GetWebSiteCount() 75 { 76 return wf.size(); 77 } 78 79 virtual ~CWebSiteFactory() 80 { 81 map<string,CWebSite*>::iterator it = wf.begin(); 82 while(it != wf.end()) 83 { 84 delete (it->second); 85 it++; 86 // wf.erase(it++); 87 } 88 } 89 }; 90 91 int main() 92 { 93 CWebSiteFactory *wf = new CWebSiteFactory(); 94 95 CWebSite *fx = wf->GetWebSiteCategory("good"); 96 CUser* user = new CUser("小菜"); 97 fx->use(user); 98 99 CWebSite *fy=wf->GetWebSiteCategory("产品展示"); 100 fy->use(new CUser("大鸟")); 101 102 CWebSite *fz=wf->GetWebSiteCategory("产品展示"); 103 fz->use(new CUser("娇娇")); 104 105 106 CWebSite *f1=wf->GetWebSiteCategory("博客"); 107 f1->use(new CUser("老顽童")); 108 109 CWebSite *f2=wf->GetWebSiteCategory("博客"); 110 f2->use(new CUser("涛涛")); 111 112 cout << wf->GetWebSiteCount() << endl; 113 return 0; 114 }
2014-12-08 20:33:43