首页 > 编程语言 >设计模式C++005__桥模式

设计模式C++005__桥模式

时间:2024-07-25 19:18:12浏览次数:9  
标签:__ string void virtual 005 ........ message 设计模式 public

设计模式C++005__桥模式

也是组合模式 的具体体现。

1、动机:

由于某些类型的古有的实现逻辑,使得他们具有两个变化的维度,乃至多个维度的变化。
?如何应对这种“多维度的变化”,如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度。

2、桥模式:

将抽象部分(业务功能)与实现部分(平台实现)分离,使他们都可以独立的变化。--GoF

3、示例:

假如有一个通信模块类Message,有一些方法:Login, SendMessage(), SendPicture(), 还有一些方法:PlaySound(),DrawShape(),WriteText(),Connect()
假设我们需要同时支持PC和Mobile平台.就可以新增两个类,分别继承Message,实现具体方法。
然后又有需求,需要每个平台要有精简版和完美版。
以PC端精简版,为例:需要登录{联网},发送消息{输入文字},发送图片{选图}的基本功能。
以PC端完美版为例:需要登录{联网,同时播放声音};发送消息时{输入文字,同时播放声音},发送图片{选图,播放声音}

Mobile,也和PC端业务功能基本一致。

如果采用继承实现如下:

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(){
        //==========
    }
};

//业务抽象

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();
        //........
    }
};



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();
}

针对Lite版本,PC和Mobile大部分是一样函数调用。我们发现继承导致子类膨胀了。可以使用组合的方式替代继承,将功能的编译时装配推迟到运行时。


class PCMessagerLite  {
PCMessagerBase *message;
public:
    
    virtual void Login(string username, string password){
        
        message->Connect();//指针调用
        //........
    }
    virtual void SendMessage(string message){
        
        message->WriteText();//指针调用
        //........
    }
    virtual void SendPicture(Image image){
        
        message->DrawShape();//指针调用
        //........
    }
};



class MobileMessagerLite {
MobileMessagerBase *message;

public:
    
    virtual void Login(string username, string password){
        
        message->Connect();//指针调用
        //........
    }
    virtual void SendMessage(string message){
        
        message->WriteText();//指针调用
        //........
    }
    virtual void SendPicture(Image image){
        
        message->DrawShape();//指针调用
        //........
    }
};

又发现可以重构的点,PCMessagerBase *message; MobileMessagerBase *message; 这两个变量有相同的基类。
进而,把他们合并为一个基类Messager :

class PCMessagerLite  {
Messager *message;  //利用组合替代继承之后,未来,运行时就是PCMessagerBase 类了 
public:
    
    virtual void Login(string username, string password){
        
        message->Connect();//指针调用
        //........
    }
    virtual void SendMessage(string message){
        
        message->WriteText();//指针调用
        //........
    }
    virtual void SendPicture(Image image){
        
        message->DrawShape();//指针调用
        //........
    }
};


class MobileMessagerLite {
Messager *message; //未来,运行时就是MobileMessagerBase 类了。

public:
    
    virtual void Login(string username, string password){
        
        message->Connect();//指针调用
        //........
    }
    virtual void SendMessage(string message){
        
        message->WriteText();//指针调用
        //........
    }
    virtual void SendPicture(Image image){
        
        message->DrawShape();//指针调用
        //........
    }
};

进而,两个类class PCMessagerLite,class MobileMessagerLite可以合二为一了,合并为MessagerLite类。

class MessagerLite  {
Messager *message;  //利用组合替代继承之后,未来,运行时就是PCMessagerBase 类(或者MobileMessageBase)了 。但是有一个问题,这里的PCMessagerBase /MobileMessagerBase 是一个抽象类,运行时new出来的是一个纯虚类。运行时创建的 new PCMessagerBase(); 对象,里面的函数都是虚函数。不可以调用。 我把该类再继承自Message呢?也不太行,MessagerLite  只实现了Message的部分虚成员函数。C++中父类声明的所有虚函数,子类是必须要实现的。
public:C++中父类声明的所有虚函数,子类是必须要实现的。
    
    virtual void Login(string username, string password){
        
        message->Connect();//指针调用
        //........
    }
    virtual void SendMessage(string message){
        
        message->WriteText();//指针调用
        //........
    }
    virtual void SendPicture(Image image){
        
        message->DrawShape();//指针调用
        //........
    }
};

class PCMessagerPerfect和class MobileMessagerPerfect;同样可以合并,为:MessagerPerfect

class MessagerPerfect {
Messager *message;   //利用组合替代继承之后,未来,运行时就是PCMessagerBase 类(或者MobileMessageBase)了 。但是有一个问题,这里的PCMessagerBase /MobileMessagerBase 是一个抽象类,运行时new出来的是一个纯虚类。运行时创建的 new PCMessagerBase(); 对象,里面的函数都是虚函数。不可以调用。 我把该类再继承自Message呢?也不太行,MessagerPerfact  只实现了Message的部分虚成员函数。C++中父类声明的所有虚函数,子类是必须要实现的。
public:
    
    virtual void Login(string username, string password){
        
        message->PlaySound();
        //********
        message->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        message->PlaySound();
        //********
        message->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        message->PlaySound();
        //********
        message->DrawShape();
        //........
    }
};

上述代码的问题:
利用组合替代继承之后,未来,运行时就是PCMessagerBase 类(或者MobileMessageBase)了 。但是有一个问题,这里的PCMessagerBase /MobileMessagerBase 是一个抽象类,运行时new出来的是一个纯虚类。运行时创建的 new PCMessagerBase(); 对象,里面的函数都是虚函数。不可以调用。 我把该类再继承自Message呢?也不太行,MessagerPerfact 只实现了Message的部分虚成员函数。C++中父类声明的所有虚函数,子类是必须要实现的。
这里如何解决呢??

必须拆分父类中的虚函数。拆分到两个类中。
Messager{Login(),SendMessage(),SendPicture}
class MessagerImp{PlaySound(),DrawShape,WriteText,Connect}

class Messager{
public:
    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:
    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual MessagerImp(){}
};

//然后
//class MessagerLite, class MessagerPerfect; 拆分后,这两个类的结构是这样的。

class MessagerLite : public Message {
MessagerImpl *messageImpl;  //...
    
    virtual void Login(string username, string password){
        
        messageImpl->Connect();//指针调用
        //........
    }
    virtual void SendMessage(string message){
        
        messageImpl->WriteText();//指针调用
        //........
    }
    virtual void SendPicture(Image image){
        
        messageImpl->DrawShape();//指针调用
        //........
    }
};

class MessagerPerfect: public Message {
MessagerImpl *messageImpl;    //...
public:
    
    virtual void Login(string username, string password){
        
        messageImpl->PlaySound();
        //********
        messageImpl->Connect();
        //........
    }
    virtual void SendMessage(string message){
        
        messageImpl->PlaySound();
        //********
        messageImpl->WriteText();
        //........
    }
    virtual void SendPicture(Image image){
        
        messageImpl->PlaySound();
        //********
        messageImpl->DrawShape();
        //........
    }
};

同样的画面又出现了。

马丁·秃了告诉我们,如果不同类当中,如果多次声明了继承自同一个父类的子类指针时,可以抽取一层抽象层。把这个子类对象放到一个抽象类里面。这里我们刚好有一个Message抽象类,把它作为Message的一个成员变量即可。

class Messager{
protected:
     MessagerImp* messagerImp;//...
public:
  Message(MessagerImp* msgImp):messagerImp(msgImp){}//父类的构造函数中要给这个成员赋值。

    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:
    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual MessagerImp(){}
};



最终版本:

class Messager{
protected:
     MessagerImp* messagerImp;//...
public:
    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:
    virtual void PlaySound()=0;
    virtual void DrawShape()=0;
    virtual void WriteText()=0;
    virtual void Connect()=0;
    
    virtual MessagerImp(){}
};


//平台实现 n
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(){
        //==========
    }
};



//业务抽象 m

//类的数目:1+n+m

class MessagerLite :public Messager {

    
public:
    //这里要有子类构造函数中要有,调用父类有参构造函数的步骤,这里是初始化列表的方式。这样才能符合构造,析构的顺序。:Messager(*msg){} -->MessagerLite(Messager *msg){}  -->~MessagerLite(){} --> ~Messager(){}。
    MessagerLite(Messager *msg):Messager(*msg){}
    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:
    
    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 Messager(mImp);
}

3、结构:

4、要点总结:

  • Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度变化,即子类化他们。
  • Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差,Bridge 模式是比多继承方案更好的解决方法。
  • Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。

标签:__,string,void,virtual,005,........,message,设计模式,public
From: https://www.cnblogs.com/wjw-blog/p/18312173

相关文章

  • 河南萌新联赛2024第(二)场:南阳理工学院
    1.D-A*BBBB原题链接:https://ac.nowcoder.com/acm/contest/87255/D根据乘法的原理,且b的每一位都相同,最终答案则是错位相加得出的结果,于是我们将a翻转,从个位开始计算,如果当前位置小于a.size就往前累加,但如果大于或等于b.size就从头开始一个一个的减(这个过程可以通过纸上手写乘法计......
  • 设计模式C++007__抽象工厂方法模式
    设计模式C++007__抽象工厂方法模式抽象工厂方法1、动机:在软件系统重,经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。?如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种封装机制,来避免客户程序和这种“多系列具体对象......
  • DataOps 新趋势:联通数科如何利用 DolphinScheduler 实现数据一体化管理
    引言在DataOps(数据运营)的推动下,越来越多的企业开始关注数据研发和运营的一体化建设。DataOps通过自动化和流程优化,帮助企业实现数据的高效流转和管理。当前,ApacheDolphinScheduler作为一款开源的分布式调度系统,凭借其灵活的插件机制和强大的调度能力,已经成为许多企业构建数据......
  • 西安理工大学机器人NEXT-E战队 视觉组简介和24届新生暑假自学指引
    视觉组简介和24届新生暑假自学指引1.视觉组是什么RoboMaster机器人竞赛作为一个竞技机器人赛事,利用弹丸攻击对方机器人或对方场地道具装甲板是取得胜利的关键。为了更好的进行打击,仅依靠操作手的手动瞄准是远远不够的,因此。视觉组利用各类算法,开发出稳定的自动瞄准系统,能够极......
  • editormd解析公式遇到的问题
    场景描述我们公司有需要将md渲染呈现到网页上的需求,内部使用了editor.md来完成该功能。但在使用的过程中碰到了如下问题部分特定的latex公式解析不正确如下latex部分$$NV_{n}=NV_{0}\timesP_{0}\timesP_{1}\timesP_{2}\times\dots\timesP_{n}$$......
  • 测试通用技术2
    一、测试流程二、软件测试过程模型V模型W模型H模型X模型三、软件测试过程理念尽早测试测试人员早期参与软件项目尽早的开展测试实行工作全面测试对软件的所有产品进行全面测试软件开发及测试人员(有时包括用户)全面参与到测试工作中全过程测试测试人员......
  • Transformer —— 李沐老师论文跟读
    论文地址:https://arxiv.org/pdf/1706.03762摘要当时的序列转录模型主要依赖于复杂的循环或者卷积神经网络加encoder+decoder架构组成,而论文提出了一种简单的网络架构transformer,在原有的encoder+decoder基础上增加注意力机制,而不使用循环和卷积。引言在引言中提到RNN的缺点......
  • locust 中HttpUser和TaskSet是什么关系
    在Locust中,HttpUser和TaskSet是用来定义用户行为和任务集合的重要组件。HttpUser:HttpUser是一个类,它代表了一个模拟的用户,可以用来模拟HTTP请求。HttpUser可以指定一些属性,比如最小等待时间和最大等待时间(min_wait和max_wait),这些属性控制了两个连续任务之间的随......
  • 栈,队列,链表
     栈堆栈又名栈(stack),它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈......
  • 二叉树的分类
    二叉树是最常见的树,二叉树的每个节点最多只有两个子节点二叉树的分类 完全二叉树 指二叉树的所有节点按照从左往右填充就像这样: 满二叉树是一种完全二叉树,当完全二叉树每个层次都被填满时,就是满二叉树例如上图中的最后一棵树堆 堆是一种带有特定排序的完全二叉......