• c++ 设计模式7 (Bridge 桥模式)


    4.2 Bridge 桥模式

    动机:

     由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个变化的维度。

    代码示例:

    实现一个Messager,含有基本功能PlaySound,Connect等,并有PC、Mobile不同的平台实现 和 精简、完美等不同业务功能的版本

    实现方法1:

    Bridge1.cpp

    类的个数:1 + n + m*n,数量巨大且不同类之中有大量重复

    重构见方法2

      1 class Messager{
      2 public:
      3     virtual void Login(string username, string password)=0;
      4     virtual void SendMessage(string message)=0;
      5     virtual void SendPicture(Image image)=0;
      6 
      7     virtual void PlaySound()=0;
      8     virtual void DrawShape()=0;
      9     virtual void WriteText()=0;
     10     virtual void Connect()=0;
     11     
     12     virtual ~Messager(){}
     13 };
     14 
     15 
     16 //平台实现
     17 
     18 class PCMessagerBase : public Messager{
     19 public:
     20     
     21     virtual void PlaySound(){
     22         //**********
     23     }
     24     virtual void DrawShape(){
     25         //**********
     26     }
     27     virtual void WriteText(){
     28         //**********
     29     }
     30     virtual void Connect(){
     31         //**********
     32     }
     33 };
     34 
     35 class MobileMessagerBase : public Messager{
     36 public:
     37     
     38     virtual void PlaySound(){
     39         //==========
     40     }
     41     virtual void DrawShape(){
     42         //==========
     43     }
     44     virtual void WriteText(){
     45         //==========
     46     }
     47     virtual void Connect(){
     48         //==========
     49     }
     50 };
     51 
     52 
     53 
     54 //业务抽象
     55 
     56 class PCMessagerLite : public PCMessagerBase {
     57 public:
     58     
     59     virtual void Login(string username, string password){
     60         
     61         PCMessagerBase::Connect();
     62         //........
     63     }
     64     virtual void SendMessage(string message){
     65         
     66         PCMessagerBase::WriteText();
     67         //........
     68     }
     69     virtual void SendPicture(Image image){
     70         
     71         PCMessagerBase::DrawShape();
     72         //........
     73     }
     74 };
     75 
     76 
     77 
     78 class PCMessagerPerfect : public PCMessagerBase {
     79 public:
     80     
     81     virtual void Login(string username, string password){
     82         
     83         PCMessagerBase::PlaySound();
     84         //********
     85         PCMessagerBase::Connect();
     86         //........
     87     }
     88     virtual void SendMessage(string message){
     89         
     90         PCMessagerBase::PlaySound();
     91         //********
     92         PCMessagerBase::WriteText();
     93         //........
     94     }
     95     virtual void SendPicture(Image image){
     96         
     97         PCMessagerBase::PlaySound();
     98         //********
     99         PCMessagerBase::DrawShape();
    100         //........
    101     }
    102 };
    103 
    104 
    105 class MobileMessagerLite : public MobileMessagerBase {
    106 public:
    107     
    108     virtual void Login(string username, string password){
    109         
    110         MobileMessagerBase::Connect();
    111         //........
    112     }
    113     virtual void SendMessage(string message){
    114         
    115         MobileMessagerBase::WriteText();
    116         //........
    117     }
    118     virtual void SendPicture(Image image){
    119         
    120         MobileMessagerBase::DrawShape();
    121         //........
    122     }
    123 };
    124 
    125 
    126 class MobileMessagerPerfect : public MobileMessagerBase {
    127 public:
    128     
    129     virtual void Login(string username, string password){
    130         
    131         MobileMessagerBase::PlaySound();
    132         //********
    133         MobileMessagerBase::Connect();
    134         //........
    135     }
    136     virtual void SendMessage(string message){
    137         
    138         MobileMessagerBase::PlaySound();
    139         //********
    140         MobileMessagerBase::WriteText();
    141         //........
    142     }
    143     virtual void SendPicture(Image image){
    144         
    145         MobileMessagerBase::PlaySound();
    146         //********
    147         MobileMessagerBase::DrawShape();
    148         //........
    149     }
    150 };
    151 
    152 
    153 void Process(){
    154         //编译时装配
    155         Messager *m =
    156             new MobileMessagerPerfect();
    157 }

    重构步骤:

    1.继承转组合,将PCMessagerBase,Mobilemessager声明为字段;

     1 class PCMessagerLite  {
     2     PCMessagerBase *messager;
     3 public:
     4     
     5     virtual void Login(string username, string password){
     6         
     7         messager -> Connect();
     8         //........
     9     }
    10     virtual void SendMessage(string message){
    11         
    12         messager -> WriteText();
    13         //........
    14     }
    15     virtual void SendPicture(Image image){
    16         
    17         messager -> DrawShape();
    18         //........
    19     }
    20 };
    21 
    22 class PCMessagerLite  {
    23     MobileMessagerBase *messager;
    24 public:
    25     
    26     virtual void Login(string username, string password){
    27         
    28         messager -> Connect();
    29         //........
    30     }
    31     virtual void SendMessage(string message){
    32         
    33         messager -> WriteText();
    34         //........
    35     }
    36     virtual void SendPicture(Image image){
    37         
    38         messager -> DrawShape();
    39         //........
    40     }
    41 };

    2.观察上述两个类,发现只有 *messager 声明不同,故采用基类声明,运行时多态调用方式,创建不同的 PCMessagerBase,Mobilemessager;

     1 class PCMessagerLite  {
     2     Messager *messager; // = new PCMessagerBase()或 MobileMessagerBase()
     3 public:
     4     
     5     virtual void Login(string username, string password){
     6         
     7         messager -> Connect();
     8         //........
     9     }
    10     virtual void SendMessage(string message){
    11         
    12         messager -> WriteText();
    13         //........
    14     }
    15     virtual void SendPicture(Image image){
    16         
    17         messager -> DrawShape();
    18         //........
    19     }
    20 };        

    3.考虑步骤2的代码,Messager类是纯虚基类(抽象类),不能实例化,故= new ...不成立。

    分析产生这种状况的原因,是Login,SendPicture等与平台实现相关的方法,和PlaySound,DrawShape等与业务功能相关的方法不应该在一个类里。

    将其拆分,得到MessagerImp类。

    同时将MessagerLite,MessagerPerfect类中相同的MesseagerImp字段提到父类Messager,得到重构后的代码

    注意运行时装配

      1 class Messager{
      2 protected:
      3      MessagerImp* messagerImp;//...
      4 public:
      5     virtual void Login(string username, string password)=0;
      6     virtual void SendMessage(string message)=0;
      7     virtual void SendPicture(Image image)=0;
      8     
      9     virtual ~Messager(){}
     10 };
     11 
     12 class MessagerImp{
     13 public:
     14     virtual void PlaySound()=0;
     15     virtual void DrawShape()=0;
     16     virtual void WriteText()=0;
     17     virtual void Connect()=0;
     18     
     19     virtual MessagerImp(){}
     20 };
     21 
     22 
     23 //平台实现 n
     24 class PCMessagerImp : public MessagerImp{
     25 public:
     26     
     27     virtual void PlaySound(){
     28         //**********
     29     }
     30     virtual void DrawShape(){
     31         //**********
     32     }
     33     virtual void WriteText(){
     34         //**********
     35     }
     36     virtual void Connect(){
     37         //**********
     38     }
     39 };
     40 
     41 class MobileMessagerImp : public MessagerImp{
     42 public:
     43     
     44     virtual void PlaySound(){
     45         //==========
     46     }
     47     virtual void DrawShape(){
     48         //==========
     49     }
     50     virtual void WriteText(){
     51         //==========
     52     }
     53     virtual void Connect(){
     54         //==========
     55     }
     56 };
     57 
     58 
     59 
     60 //业务抽象 m
     61 
     62 //类的数目:1+n+m
     63 
     64 class MessagerLite :public Messager {
     65 
     66     
     67 public:
     68     
     69     virtual void Login(string username, string password){
     70         
     71         messagerImp->Connect();
     72         //........
     73     }
     74     virtual void SendMessage(string message){
     75         
     76         messagerImp->WriteText();
     77         //........
     78     }
     79     virtual void SendPicture(Image image){
     80         
     81         messagerImp->DrawShape();
     82         //........
     83     }
     84 };
     85 
     86 
     87 
     88 class MessagerPerfect  :public Messager {
     89     
     90    
     91 public:
     92     
     93     virtual void Login(string username, string password){
     94         
     95         messagerImp->PlaySound();
     96         //********
     97         messagerImp->Connect();
     98         //........
     99     }
    100     virtual void SendMessage(string message){
    101         
    102         messagerImp->PlaySound();
    103         //********
    104         messagerImp->WriteText();
    105         //........
    106     }
    107     virtual void SendPicture(Image image){
    108         
    109         messagerImp->PlaySound();
    110         //********
    111         messagerImp->DrawShape();
    112         //........
    113     }
    114 };
    115 
    116 
    117 
    118 
    119 void Process(){
    120     //运行时装配
    121     MessagerImp* mImp=new PCMessagerImp();
    122     Messager *m =new Messager(mImp);
    123 }

     模式定义:

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

    类图:

    要点总结:

    Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象的实现可以沿着各自的维度来变化。所谓抽象和实现研制各自维度的变化,即“子类化”他们。

    Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个雷只有一个变化的原因),复用性较差。Bridge模式是比多继承更好的解决方案。

    Bridge模式的应用一般在“两个非常强的变化维度”有时一个类也有多余两个的变化维度,这是可以使用Bridge的扩展模式。

  • 相关阅读:
    无限循环小数化分数、
    HDU 1060
    HDU 2601
    HDU 1286
    HDU 1071
    有关SQLite的substr函数的笔记
    Android 在安装完成界面,点击打开应用程序。在应用程序点击home键,再从桌面打开程序导致产生多个实例或者说程序被重复打开
    酷派8150S(移动定制版)可用的第三方Recovery备份数据、刷机并精简系统内置APK经验
    个人经验
    批处理脚本
  • 原文地址:https://www.cnblogs.com/wangxiaobao/p/5208448.html
Copyright © 2020-2023  润新知