设计模式之结构模式(全)

 
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;
}
 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值