目录
1、Flyweight
(1)意图
运用共享技术有效地支持大量细粒的对象
(2)结构
flyweight描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。
concreteflywegiht实现flyweight接口,并为内部状态增加储存空间,concreteflyweight对向必须可共享的。它所储存的状态必须是内部的,它必须独立于concreteflyweight对象的场景。
并非所有的flyweight子类都需要被共享。flyweight接口使共享成为可能,但并不强制共享。在flyweight对象结构的某些层次,unsharedconcreteflyweight对象通常将concreteflayweight对象作为子节点。
flyweightfactory创建并非管理flyweight对象;确保合理的共享flyweight,当用户请求一个flyweight时,flyweight对象提供一个创建的实例或者在不存在时创建一个实例。
client唯一一个对flyweight的引用;计算或储存一个或多个flyweight的外部状态。
(3)适用性
一个应用程序使用了大量的对象。
完全由于使用大量的对象,造成很大开销。
对象的大多数状态都可以为外部状态。
如果删除兑现的外部状态,那么可以用相对较少共享对象取代多组对象。
应用程序不依赖于对象标识,由于flyweight对象可被共享,所以对于概念上明显有别的对象,表示测试将返回真值。
2、根据uml编写代码
(1)泛化关系
所谓泛化关系,我们简单里的理解即为为父类与子类的关系,本uml图中flyweight类为unsharedconcreteflyweigh类和concreteflayweight类的父类。
(2)关联关系
flyweightfactory为flyweight特殊关联关系聚合,即在flyweightfactory中有一个“flyweight*”指向flyweight的指针,实现对flyweight的操作。
(3)UML的理解
首先我们根据教材适用性来理解,一个应用程序使用了大量的对象;由于使用大量的对象,造成很大开销;对象的大多数状态都可以为外部状态。通过这三句话我们可以做如下理解,假如我们要开发一个卖咖啡和茶的饮料店软件,那么我们卖出一个红茶要new一个对象,我们生成一个绿茶又要new一个对象,我们做一个抹茶又要new一个对象。这样我们的茶类的商品越丰富,我们需要new的东西就越来越多。咖啡类商品也一样,奶昔咖啡要new、摩卡要new,假如咖啡种类也很多我们需要new的内容也会越来越多,这就意味着我们使用大量的对象,意味着有大量的开销
假如我们做如下假设:
奶昔咖啡=咖啡+奶昔部分;
拿铁咖啡=咖啡+拿铁部分;
如果我们这样实现程序的表现的化,奶昔咖啡和拿铁的咖啡部分就可以共用一个new。奶昔部分和拿铁部分我们可以把它理解为外部状态,在实际操作中我们可以用一个链表对外部状态进行储存,若有必要我们可以进行操作或者修改,例如飞行游戏中,飞机射出大量的子弹,我们可以享元模式中,众多子弹可以公用一个new,子弹在界面的位置可以作为外部变量存在链表之中,按时间推移,我们修改子弹的图的位置实现子弹运动的效果。
UML图中也有不允许共享的部分,这点非常好理解,还是卖咖啡和茶的饮料店的店的例子,这个饮料点如果它也卖可乐、雪碧等第三方饮料这种饮料就不存共享了。
3、代码实现
暂未写析构部分
#include<iostream>
#include<list>
using namespace std;
class taset{//用于存储外部状态
public:
taset(string mixture){
this->mixture=mixture;
}
string mixture;
};
class flyweight{//饮料店
public:
virtual void operation()=0;
virtual void operation(const string& ,const string&)=0;
string taste;
};
class concreteflyweight_tea:public flyweight{//煮茶部分
public:
void operation(){
cout<<"复杂的煮茶过程"<<endl;
cout<<"====================="<<endl;
}
void operation(const string& drinkname,const string& taset){}
};
class concreteflyweight_cofee:public flyweight{//咖啡部分
public:
void operation(){
cout<<"复杂的煮咖啡过程"<<endl;
cout<<"====================="<<endl;
}
void operation(const string& drinkname,const string& taset){}
};
class unsharedconcreteflyweight_other:public flyweight{//可乐、雪碧、芬达等外部产品,逻辑上无法使用享元模式实现共享
public:
void operation(){
}
void operation(const string& drinkname,const string& taset){
cout<<"店员制作"<<drinkname<<"加"<<taset<<endl;
cout<<"====================="<<endl;
}
};
class flyweightfactory{//享元工厂,用于对flyweight类(饮料店)的操作
public:
void getflyweight(string key, string this_taset){
if(key=="tea"or key=="茶"){
if(tea==NULL){//享元方式,第一次使用创建,后续就不再创建,直接使用。
cout<<"首次使用原味茶叶配方"<<endl;
tea=new concreteflyweight_tea();
}
else{
cout<<"原味茶叶配方已创建"<<endl;
}
findtaset(tea,this_taset);//实现外部状态
}
else if(key=="cofee"or key=="咖啡"){
if(cofee==NULL){
cout<<"首次使用原味咖啡配方"<<endl;
cofee=new concreteflyweight_cofee();
}
else{
cout<<"原味咖啡配方已创建"<<endl;
}
findtaset(cofee,this_taset);
}else{
other=new unsharedconcreteflyweight_other();
other->operation(key,this_taset);
}
}
void findtaset(flyweight *drink,string this_taset){
typedef list<taset*>::iterator IT;
for(IT it=mylist.begin();it!=mylist.end();it++){//通过对链表进行遍历,若表中存有就直接使用,没有就创建一个并存在链表中
if((*it)->mixture==this_taset){
cout<<this_taset<<"这个口味已经创建"<<endl;
drink->operation();
return ;//找到后马上return结束该方法
}
}
cout<<this_taset<<"是一个新的口味我们需要记录一下"<<endl;//在链表中没有找到
taset *newtaset=new taset(this_taset);//创建一个外部状态
mylist.push_back(newtaset);//把创建的外部状态存入list中
drink->operation();
}
private:
list<taset*>mylist;
flyweight *tea;
flyweight *cofee;
flyweight *other;//非共享
};
int main(){
flyweightfactory* a=new flyweightfactory;
a->getflyweight( "tea","抹茶" );
a->getflyweight( "茶","抹茶" );
a->getflyweight( "tea","红茶" );
a->getflyweight( "cofee","奶昔" );
a->getflyweight( "tea","红茶" );
a->getflyweight( "tea","红茶" );
a->getflyweight( "咖啡","奶昔" );
a->getflyweight( "可乐","冰" );
return 0;
}
运行结果: