II 结构型模式(7)
Bridge
Adapter
Decorator
Composite
Flyweight
Facade
Proxy
1,Bridge(桥模式),它的作用主要是应付这么一种情况:开始时,系统已经做好,后来,客户要求变化了,于是要重新设计类,由于软件维护的周期很长,所以类的数目不断膨胀,使得最后难于维护.这里的做法是. 实现两个部分,一部分实现功能,另一部分使用功能:
客户总是使用AbsCls生成的指针, 而实际情况是: AbsCls的指针指向Cls对象,为了实现要求的功能Op, Cls有一个AbsClsImp类型的指针, 调用时,根据需要调用ClsImp_A或者ClsImp_B的方法Operation!! 当需求变更时,只要增加ClsImp_X就好,这实在是鬼斧神工!
class AbsClsImp
{
public:
virtual void Operation()=0;
};
class ClsImpA:public AbsClsImp
{
public:
void Operation() { cout<<"ClsImpA::Operation/n"; }
};
class ClsImpB:public AbsClsImp
{
public:
void Operation() { cout<<"ClsImpB::Operation/n"; }
};
class AbsCls
{
public:
virtual void Op()=0;
AbsClsImp*pImpObj;
};
class Cls:public AbsCls
{
public:
void Op() { pImpObj->Operation(); }
};
int main()
{
AbsClsImp*pImpObj=new ClsImpA;
AbsCls*pObj=new Cls();
pObj->pImpObj=pImpObj;
pObj->Op();
return 0;
}
现在,客户需求变化时,只要去右边做修改就行了,左边的结构基本可以不变.
2, Adapter (适配器)
工作中,可能出现这种情况,来了一个任务,团队中没有人能胜任, 但团队外有一人X能胜任,这时有两种解决办法:
一,将那人招入团队;
二,让团队中的A负责该任务,A再向X请教,从而完成任务.
又有一个事实,为加快开发速度,可购买第三方的库,而这个”第三方的库”里的接口与我们要求的不可能完全吻合(除非是定制), 这时为了使用这个库,必须用一个适配器,调用这个不完全吻合的库的接口. 这就是Adapter 设计模式.
(I),“将那人招入团队”的做法对应”Adapter对象模式”:
class MyCls
{
public:
virtual void Op(){ cout<<"MyCls::Op/n"; } //自己解决任务,无法胜任的
};
class Adaptee
{
public:
void Operation(){ cout<<"Adaptee::Operation/n"; }//第三方库能够解决问题
}; //不用virtual型,因为没有预见会被购买
class Adapter:public MyCls
{
public:
Adapter(Adaptee*pAdaptee):_pAdaptee(pAdaptee){ }
void Op(){ _pAdaptee->Operation(); } //适配器精髓
private:
Adaptee*_pAdaptee; //这个对象不应该在MyCls中使用,因为MyCls并不知道Adaptee
};
int main()
{
Adaptee*pAdaptee=new Adaptee;
MyCls* pObj=new Adapter(pAdaptee);
pObj->Op(); //看上去是自己(MyCls)实现的, 其实调用的是第三方库(Adaptee)
return 0;
}
(II),”让A负责,然后A向X请教”对应”Adapter类模式”
上面的Adapter中使用了一个Adaptee指针,在类模式中,应该私有继承Adapter:private Adaptee, 这里,有<<Effective C++>>中的做法, 私有继承只是”用..实现”
class MyCls
{
public:
virtual void Op(){ cout<<"MyCls::Op/n"; }
};
class Adaptee
{
public:
void Operation(){ cout<<"Adaptee::Operation/n"; }//同样,不用virtual型
};
class Adapter:public MyCls,private Adaptee
{
public:
void Op(){ Operation(); }
};
int main()
{
MyCls* pObj=new Adapter;
pObj->Op();
return 0;
}
3,Decorator (很多人说装饰器,个人认为说油漆工更好)
常常,为了给已有类增加新的功能,我们会为这个类派生出一个新的类,然后增加新功能(如MFC编程中就常这么做),如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的.
使用Decorator的理由是:这些功能需要由用户动态决定加入的方式和时机.Decorator提供了"即插即用"的方法,在运行期间决定何时增加何种功能.对下面的图而言,就是不用再改变已投付使用的ConCreateCom类, 而只要适当地改变ConcreateDec类即可,然后在需要使用扩展了功能的ConCreateCom的地方使用ConcreateDec.
图中,ConcreateDec使用一个Component指针,可以泛化多个ConcreateCom类型,至于为什么不用Decorator而要派生一个它的子类,显然是为了结构化,有时,我们甚至可以派生多个ConcreateDec类型.
下面的代码假设ConCreateCom已可以打印”World”, 但现在要新增功能,要求在World前面要打印Hello字样,代码如下:
class Component
{
public:
virtual void operation(){}
};
class ConcreateCom:public Component
{
public:
void operation(){ cout<<"World/n"; }
};
class Decorator:public Component
{
public:
Decorator(Component*pCom){ _pCom=pCom; }
protected:
Component*_pCom; //这里用protected修饰很必要,使得在所有Decorator的派生类中都有一个可用
}; //的Component类型指针!!
class ConcreateDec:public Decorator
{
public:
void AddOp(){ cout<<"Hello "; } //这就是新增功能,不能在Decorator类中声明,因为Decorator
//中无法预见ConcreateCom类将要扩展AddOp功能.
ConcreateDec(Component*pCom):Decorator(pCom){} //注意这里只构造了Decorator
void operation() //这是effective C++中"派生类对象首先是一个
{ //基类对象" 说法的实现.
AddOp(); //现在能够打印 Hello 了
_pCom->operation(); //这里打印World
}
};
int main()
{
Component*pCom=new ConcreateCom;
Decorator*pDec=new ConcreateDec(pCom);
pDec->operation();
return 0;
}
4,Composite(合成模式)
该模式用来组合一个对象(Component)的各个部分(Leaf), 常用”树形”做比喻,树本身是一个整体(Component),它的功能由多个叶子完成(Leaf),这个让多个部分共同完成整体功能的任务交给(Composite)组合器来实现.
如下图: Composite有一个vector<Component*>型的向量,实际用来管理的是一系列的Leaf对象指针, 当Component对象要完成它的Operation时,Composite就遍历它的向量,调用每个Leaf的Operation.
这个模式很容易产生其他的变体, 比如可以只定义一个Leaf类,通过传递不同的参数构造不同的对象,实现不同版本的Operation. 或者还可以将Life也作为抽象类,以供派生等.
代码:
class Component
{
public:
virtual void Operation()=0;
virtual Component* GetChild(unsigned int index){ cout<<"Leaf can not get a child/n";return 0; };
virtual void Add(Component*com){ cout<<"Leaf can not Add a leaf/n"; };
virtual void Remove(Component*com){ cout<<"Leaf can not Remove a leaf/n"; };
};
class LeafA:public Component
{
public:
void Operation(){ cout<<"LeafA::Operation/n"; }
};
class LeafB:public Component
{
public:
void Operation(){ cout<<"LeafB::Operation/n"; }
};
class Composite:public Component
{
public:
void Operation()
{
vector<Component*>::iterator it_com;
for (it_com=m_vec_com.begin();it_com!=m_vec_com.end();it_com++)
{
(*it_com)->Operation();
}
}
void Add(Component*com){ m_vec_com.push_back(com); }
void Remove(Component*com) { m_vec_com.erase(&com); }
Component*GetChild(unsigned int index) { return m_vec_com[index]; }
private:
vector<Component*>m_vec_com;
};
int main()
{
Component*com_A=new LeafA;
Component*com_B=new LeafB;
Composite*pComposite=new Composite;
pComposite->Add(com_A);
pComposite->Add(com_B);
pComposite->Operation();//会遍历所有Leaf,并调用它们的Operation
//下面这段代码才是客户端使用的代码,它用Component*指针来调用合适的Leaf的Operation
Component*com=pComposite->GetChild(0);
com->Operation();
com=pComposite->GetChild(1);
com->Operation();
pComposite->Remove(com);
return 0;
}
5,Flyweight (共享元)
有时,在程序设计中要生成非常多的对象,这时就会耗费大量的空间,而如果这些对象有很多相同之处,则可以尝试对象的复用,这就是共享元模式的做法. 比如:Flyweight是”字母”,字母A是ConcreateFlyweight的一个对象, 文档中出现1000个A时,如果有共享元模式就很有优势. 这时要注意,每个A不一定相同,比如字体,大小等,这些可设为”外部信息”,但”值为A”却是每个A的相同之处,设为”内部信息”,共享的只是内部信息. 当用户Client要生成一个字母(Flyweight)时,它向FlyweightFactory发出请求, 而FlyweightFactory维护着一vector<Flyeighe*>向量, 如果向量中有要找的字母,则直接使用即可,如果没有,则再生成一个,并加入到向量中,以备下次之用.
另外,可能由于某种原因,有些Flyweight对象不是允许被共享的,因此下面的图中还有一个UnshareConcreateFW类.
针对这张UML图,代码如下,但并实现UnshareConcreateFW类.
class Flywight
{
public:
virtual string* GetString()=0;
protected:
string _Constr;
};
class ConcreateFlyweight:public Flywight // ConcreateFlyweight就是"共享元".
{
public:
ConcreateFlyweight(string str) { _Constr=str; }
string* GetString(){ string* str=new string(_Constr); return str; }//返回自身成员
};
class FlywightFactory //"共享元"工厂.
{
public:
Flywight* GetFlyweight(string key) //获取Flyweight,如果已存在,则直接得到,如果不存在
{ //则生成一个再返回它.
for (vector<Flywight*>::iterator it_fw=m_vec_fw.begin(); it_fw!=m_vec_fw.end();it_fw++)
{
if (key==*((*it_fw)->GetString())) //判断
{
cout<<"Flyweight is already exist!/n";
return *it_fw;
}
}
cout<<"Create a new Flyweight/n";
Flywight*pFw= new ConcreateFlyweight(key);
m_vec_fw.push_back(pFw);
return pFw;
}
private:
vector<Flywight*>m_vec_fw;
};
int main()
{
FlywightFactory*pfwf=new FlywightFactory;
pfwf->GetFlyweight("hello");
pfwf->GetFlyweight("world");
pfwf->GetFlyweight("hello"); //第二次获取成员为"hello"的Flyweight对象时,由于已经存在
//故不再创建,而直接返回该对象.
return 0;
}
6,Façade(门面)
假设有若干个库(SubSystem)实现了若干个接口(operation), 这若干个接口共同完成某个功能,现在调用者(client)很郁闷,因为他必须去到这些库里面分别调用它们的接口,自从有了Façade模式,生活变成不再郁闷! 让Façade当中介调用各个接口,client只要调用Façade的”统一”接口就行了. 以现实生活中的”办证”为例,要补办学生证,要跑东跑西打证明,最后才能把证办下来,Façade的做法是专门找个人给我办证,我只负责接收办好的学生证.
class SubSystem_A
{
public:
void Operation_A(){ cout<<"This department SubSystem_A/n"; }
};
class SubSystem_B
{
public:
void Operation_B(){ cout<<"This department SubSystem_B/n"; }
};
class Facade
{
public:
Facade(){ pSubA=new SubSystem_A; pSubB=new SubSystem_B; }
void DotheJob(){ pSubA->Operation_A(); pSubB->Operation_B(); }
private:
SubSystem_A* pSubA;
SubSystem_B* pSubB;
};
int main()
{
Facade*pFa=new Facade;
pFa->DotheJob(); //实际执行了Subsystem_A/B它们的Operation_A/B.
return 0;
}
这种做法看上去扩展性不够好,因为扩展一个SubSystem_X就要新增一个相应的指针,但这也是它的特点,当要增加新的功能时,可以在已有的某个SubSystem里实现新的功能,也可以再定义一个全新的SubSystem类.
7,Proxy(代理).
有时候,如显示一幅大图片(虚代理),为远程对象创建一个本地镜像(远程代理),用户很多的论坛权限赋予(保护代理),需要用到一个代理(Proxy)去”代表本人”完成任务.Proxy模式最大的好处就是实现了逻辑和实现的彻底解耦。
class Subject
{
public:
virtual void Operation(){ cout<<"Subject::Operation can not do it well/n"; }
};
class RealSubject:public Subject
{
public:
void Operation(){ cout<<"RealSubject::Operation does a good job/n"; }
};
class Proxy:public Subject //在本例中,Proxy不从Subject也可以完成任务,但从Subject是有好处的,
{ //如果这个Subject类有很多方法,Proxy就必须从Subject派生了,以免出错
public:
Proxy(Subject*pObj){ this->_pObj=pObj; }
void Operation(){ _pObj->Operation(); }
private:
Subject*_pObj;
};
int main()
{
Subject*pObj=new RealSubject;
Proxy* pPro=new Proxy(pObj);
pPro->Operation();
return 0;
}
1437

被折叠的 条评论
为什么被折叠?



