“单一职责”模式
单一职责模式出现的原由是:在软件设计中,如果出现责任划分不清楚,使用继承得到的结果往往会随需求的变化,子类急剧膨胀,同时充斥重复代码,这个时候的关键就是划清责任。
桥模式
A:说明
桥模式的动机:由于某些类型的固有的实现逻辑,使得他们具有多个变化得维度,带来子类膨胀和重复代码的问题。
B:例子(不同平台的邮件信箱收发邮件的实现)
1)首先我们想到是一堆的功能接口,将其所有功能接口放到一个纯虚类中,作为基类。同时有想到支持的平台主题,包括PC和Mobile,并继承接口定义的基类,并实现相关平台操作的接口(播放声音,画线等等)。并根据需求推出平台的不同版本,具体UML和代码如下:
class Messager{
public:
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual void PlaySound()=0; //往下接口,各个平台的实现是不一样的
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~Messager(){}
};
//平台主体类实现
class PCMessagerBase : public Messager{
public:
virtual void PlaySound(){
//**********
}
virtual void DrawShape(){
//**********
}
virtual void WriteText(){
//**********
}
virtual void Connect(){
//**********
}
};
class MobileMessagerBase : public Messager{
public:
virtual void PlaySound(){
//==========
}
virtual void DrawShape(){
//==========
}
virtual void WriteText(){
//==========
}
virtual void Connect(){
//==========
}
};
//业务抽象
//PC经典版
class PCMessagerLite : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::DrawShape();
//........
}
};
//PC完美版
class PCMessagerPerfect : public PCMessagerBase {
public:
virtual void Login(string username, string password){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
PCMessagerBase::PlaySound();
//********
PCMessagerBase::DrawShape();
//........
}
};
//手机经典版
class MobileMessagerLite : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::DrawShape();
//........
}
};
//手机完美版
class MobileMessagerPerfect : public MobileMessagerBase {
public:
virtual void Login(string username, string password){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::Connect();
//........
}
virtual void SendMessage(string message){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::WriteText();
//........
}
virtual void SendPicture(Image image){
MobileMessagerBase::PlaySound();
//********
MobileMessagerBase::DrawShape();
//........
}
};
void Process(){
//编译时装配
Messager *m = new MobileMessagerPerfect();
}
上述的设计也存在缺陷,主要集中在,后期需求变大,子类的数量也会剧增,同时也存在结构上的代码重复(PCMessagerLite ::Login和MobileMessagerLite::Login 在代码结构逻辑上存在重复)。
2)根据设计原则:组合优于继承。重构代码如下:
class PCMessagerLite {
protected:
Messager* messager; //= new PCMessagerBase();
public:
virtual void Login(string username, string password){
messager->Connect();
//........
}
virtual void SendMessage(string message){
messager->WriteText();
//........
}
virtual void SendPicture(Image image){
messager->DrawShape();
//........
}
};
//手机经典版
class MobileMessagerLite {
protected:
Messager* messager; //= new MobileMessagerBase();
public:
virtual void Login(string username, string password){
messager->Connect();
//........
}
virtual void SendMessage(string message){
messager->WriteText();
//........
}
virtual void SendPicture(Image image){
messager->DrawShape();
//........
}
};
上述代码修改由编译时装配改为运行时装配,修改后的PcMessagerLite和MobileMessagerLite一模一样,可以设计为同一个类。类似的有关Perfect类也可以这样操作。
//经典版
class MessagerLite {
protected:
Messager* messager; //new PCMessagerBase() / MobileMessagerBase()
public:
virtual void Login(string username, string password){
messager->Connect();
//........
}
virtual void SendMessage(string message){
messager->WriteText();
//........
}
virtual void SendPicture(Image image){
messager->DrawShape();
//........
}
};
//完美版
class MessagerPerfect{
protected:
Messager* messager;// new PCMessagerBase() / MobileMessagerBase()
public:
virtual void Login(string username, string password){
messager->PlaySound();
//********
messager->Connect();
//........
}
virtual void SendMessage(string message){
messager->PlaySound();
//********
messager->WriteText();
//........
}
virtual void SendPicture(Image image){
messager->PlaySound();
//********
messager->DrawShape();
//........
}
};
上述的代码信息的会发现编译不会通过。 原因是Messager是个纯虚基类,而PcMessagerBase和MobileMessagerBase并没有全部实现所有纯虚函数,同样MessagerLite和MessagerPerfect也没有。造成这种原因的是纯虚基类里定义了多个变化/功能的维度。因此就需要拆分纯虚基类。代码如下
class Messager{
public:
Messager(){}
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
class MessagerImp{
public:
MessagerImp(){}
virtual void PlaySound()=0; //往下接口,各个平台的实现是不一样的
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~MessagerImp(){}
};
//平台主体类实现
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 {
protected:
MessagerImp* messagerImp; //new PCMessagerBase() / MobileMessagerBase()
public:
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{
protected:
MessagerImp* messagerImp;// new PCMessagerImp() / MobileMessagerImp()
public:
virtual void Login(string username, string password){
messagerImp->PlaySound();
//********
messagerImp->Connect();
//........
}
virtual void SendMessage(string message){
messagerImp->PlaySound();
//********
messager->WriteText();
//........
}
virtual void SendPicture(Image image){
messagerImp->PlaySound();
//********
messagerImp->DrawShape();
//........
}
};
3)再根据马丁.福勒 重构原则里,提到需要将子类里重复的变量往上提,代码如下:
class Messager{
protected:
MessagerImp* _imp;
public:
Messager(MessagerImp* imp):_imp(imp){}
virtual void Login(string username, string password)=0;
virtual void SendMessage(string message)=0;
virtual void SendPicture(Image image)=0;
virtual ~Messager(){}
};
class MessagerImp{
public:
MessagerImp(){}
virtual void PlaySound()=0; //往下接口,各个平台的实现是不一样的
virtual void DrawShape()=0;
virtual void WriteText()=0;
virtual void Connect()=0;
virtual ~MessagerImp(){}
};
//平台主体类实现
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* imp):Messager(imp){}
~MessagerLite(){}
virtual void Login(string username, string password){
_imp->Connect();
//........
}
virtual void SendMessage(string message){
_imp->WriteText();
//........
}
virtual void SendPicture(Image image){
_imp->DrawShape();
//........
}
};
//完美版
class MessagerPerfect: public Messager{
public:
MessagerPerfect(MessagerImp* imp):Messager(imp){}
~MessagerPerfect(){}
virtual void Login(string username, string password){
_imp->PlaySound();
//********
_imp->Connect();
//........
}
virtual void SendMessage(string message){
_imp->PlaySound();
//********
_imp->WriteText();
//........
}
virtual void SendPicture(Image image){
_imp->PlaySound();
//********
_imp->DrawShape();
//........
}
};
void Process(){
//运行时装配
MessagerImp* pc = new PcMobileMessagerImp();
Messager* msgLite = new MessagerLite(pc);
}
上述的过程就是桥模式,回顾前面的,我们这个需求有两个变化的维度,一个是平台实现的变化,一个是业务功能的变化。这俩个变化的方向带动行为的多态的实现应该也是往不同方向发展,不应该放到同一个类中。这就桥模式的思想。
C:总结
1,根据设计模式的原则:将抽象部分(业务功能)和实现部分(平台实现)分离,使它们都可以独立的变化。结构UML如下:
红框里是稳定的部分,蓝框是变化的部分,设计模式将稳定的部分和变化的部分分离开。
2,桥模式是使用“对象间的组合关系”解耦了抽象和实现之间的固有绑定关系,使其沿着各自维度变化。一般用在“多个非常强的变化维度”时。