某些类的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个纬度的变化。例如:
class Messager{
public:
/*
下面三个函数是具体的业务层面的要求,比如实现用户登录功能,
在用户登陆时发送消息和图片
*/
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
/*
下面四个函数是平台相关的,不同的平台对play、draw、write
和connect有不一样的实现
*/
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager(){}
};
下面是PC和移动两个平台的实现类
class PCMessager : public Messager{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessager : public Messager{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
下面是PC和移动两个平台上具体的业务要求,比如两个平台都要做一个精简版和一个完美版。
class PCMessagerLite : public PCMessager{
public:
virtual void Login(string username, string password){
PCMessager::Connect();
//........
}
virtual void SendMessage(string message){
PCMessager::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessager::DrawShape();
//........
}
};
class PCMessagerPerfect : public PCMessager {
public:
virtual void Login(string username, string password){
PCMessager::PlaySound();
//********
PCMessager::Connect();
//........
}
virtual void SendMessage(string message){
PCMessager::PlaySound();
//********
PCMessager::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessager::PlaySound();
//********
PCMessager::DrawShape();
//........
}
};
class MobileMessagerLite : public MobileMessager {
public:
virtual void Login(string username, string password){
MobileMessager::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessager::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessager::DrawShape();
//........
}
};
class MobileMessagerPerfect : public MobileMessager {
public:
virtual void Login(string username, string password){
MobileMessager::PlaySound();
//********
MobileMessager::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessager::PlaySound();
//********
MobileMessager::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessager::PlaySound();
//********
MobileMessager::DrawShape();
//........
}
};
void Process(){
//编译时装配
Messager *m = new MobileMessagerPerfect();
}
从上面抽象类Messager可以看出,业务层面要求和平台实现相关其实是事务的两个方面,在类设计时不应该强行将它们放在一起,应该解耦它们之间固有的绑定关系,使得两者可以沿着各自的维度来变化。
/*
平台实现类接口,具体的实现由各自平台完成
*/
class MessagerImp{
public:
virtual void PlaySound()=0;
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual MessagerImp(){}
};
/*
业务要求类接口,引入平台实现类多态指针messagerImp,
实现了晚绑定。其实不管是登陆还是发送消息还是发送图像,
它们都依赖于具体的平台实现,而MessagerImp作为具体平台
实现类的基类,扮演了“桥”的角色,因此自然而然地要在
Messager类中引入messagerImp这个多态指针。
*/
class Messager{
protected:
MessagerImp* messagerImp;//...
public:
Messager(MessagerImp* mImp):messagerImp(mImp){
}
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
/*具体平台实现类*/
class PCMessagerImp : public MessagerImp{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerImp : public MessagerImp{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
/*精简版和完美版实现类*/
class MessagerLite :public Messager {
public:
MessagerLite(MessagerImp* mImp):Messager(mImp){
}
virtual void Login(string username, string password){
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->DrawShape();
//........
}
};
class MessagerPerfect : public Messager {
public:
MessagerPerfect(MessagerImp* mImp):Messager(mImp){
}
virtual void Login(string username, string password){
messagerImp->PlaySound();
//********
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->PlaySound();
//********
messagerImp->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->PlaySound();
//********
messagerImp->DrawShape();
//........
}
};
void Process(){
//运行时装配
MessagerImp *mImp = new PCMessagerImp();
Messager *m = new MessagerPerfect(mImp);
}
由上可见,不管是mobile还是PC,完美版的处理都有类MessagerPerfect来完成,精简版的处理都由类MessagerLite来完成,避免了在各自平台上分别实现这两种版本。
不管是从上面的桥模式还是之前谈到的装饰器模式,可以通俗地总结出下面的原则。**如果动作要去处理对象,在动作和对象都存在多种情况时,比如动作(存在PC和移动两种实现方式),对象(存在精简和完美两种版本),那么最终设计出来的动作类要能同时处理各个种类的对象(比如PCMessagerImp能处理PC上面的完美和精简两种版本,MobileMessagerImp能处理移动平台上面的完美和精简两种版本),而不是为各种种类的对象分别设计各自的动作处理类。如何让动作类能同时处理各个种类的对象,这就需要利用各个对象共有的基类指针的多态性来实现。 **
上面讨论的是动作类同时处理各个种类的对象,那么反之也一样,即每个种类的对象也要能适应各个动作的处理,这时就利用各个动作共有的基类指针的多态性来实现了。