• 桥接模式


    参考:https://www.cnblogs.com/wenlong/p/5255671.html

    1、作用

           当类的模型有两个或多个维度的时候,如果两个变化维度用同一个类使用继承方式实现会变得很复杂(冗余代码很多),不易于维护和扩展(继承关系是一种强耦合关系),为了降低耦合关系,提高维护性和可扩展性,可以将两个变化维度的通过两个类(abstruction、implementor类)来实现,将两个类的关系为弱耦合的关联关系,这样就可以提高程序的扩展性和可维护性。

          拿汽车在路上行驶的来说。既有小汽车又有公共汽车,它们都不但能在市区中的公路上行驶,也能在高速公路上行驶。这你会发现,对于交通工具(汽车)有不同的类型,它们所行驶的环境(路)也有不同类型,在软件系统中就要适应两个方面(不同车型,不同道路)的变化,怎样实现才能应对这种变化呢?

    如果使用继承关系来实现,对应的UML图为如下:

     这个模型中有路和汽车两个变化维度,第一次继承是扩展路的维度、第二次继承是扩展汽车的维度,两个维度是一个cross的关系,加入有10种路,10种汽车就会要继承出10*10+10个类,数量是指数增长的,也就是说扩展性很差,并且扩展出来的代码会有很多冗余的代码。

    Road.h

    #include <iostream>
    
    
    #ifndef __ROAD__H__
    #define __ROAD__H__
    
    using namespace std;
    
    class Road {
        public:
            virtual void run() = 0;
    };
    
    
    class SpeedWay: public Road {
        public:
            void run() override {
                cout<<"run on the speed way"<<endl;
            }
    };
    
    
    class Street: public Road {
        public:
            void run() override {
                cout<<"run on the street"<<endl;
            }
    };
    
    class CarOnSpeedWay: public SpeedWay {
        public:
            void run() override {
                cout<<"Car run on the speed way"<<endl;
            }
    };
    
    class BusOnSpeedWay: public SpeedWay {
        public:
            void run() override {
                cout<<"Bus run on the speed way"<<endl;
            }
    };
    
    class CarOnStreet: public Street {
        public:
            void run() override {
                cout<<"Car run on the Street"<<endl;
            }
    };
    
    class BusOnStreet: public Street {
        public:
            void run() override {
                cout<<"Bus run on the Street"<<endl;
            }
    };
    
    #endif

    test.cc

    #include "Road.h"
    
    int main() {
        Road *carOnSpeedway = new CarOnSpeedWay;
        Road *busOnSpeedway = new BusOnSpeedWay;
        Road *carOnStreet    = new CarOnStreet;
        Road *busOnStreet    = new BusOnStreet;
    
        carOnSpeedway->run();
        busOnSpeedway->run();
        carOnStreet->run();
        busOnStreet->run();
    
    
        return 0;
    }

    输出:

    缺点:
         但是我们说这样的设计是脆弱的,仔细分析就可以发现,它还是存在很多问题,首先它在遵循开放-封闭原则的同时,违背了类的单一职责原则,即一个类只有一个引起它变化的原因,而这里引起变化的原因却有两个,即路类型的变化和汽车类型的变化;其次是重复代码会很多,不同的汽车在不同的路上行驶也会有一部分的代码是相同的;

    再次是类的结构过于复杂,继承关系太多,难于维护,最后最致命的一点是扩展性太差。如果变化沿着汽车的类型和不同的道路两个方向变化,我们会看到这个类的结构会迅速的变庞大。

    如果要增加一种路和车型,比如StateRoad和Moto,得到的UML图就是复杂很多。

     增加了2种类型,却增加了6个类,且类型越多时,往后扩展,增加的类越多。主要原因是两个变化维度进行了cross,如果把两个维度进行独立开来,分开扩展就能实现某一个维度增加一种类型,只增加一个类,cross的操作,由用户来把握,这就要使用桥接模式。

    2、实现方式

    将两个变化维度分为两个基类(abstraction,implementor类中来实现),则两个类的关系为关联关系,而不是继承关系。如何将两个类关联在一起由用户的需求来选择。

     同样是上面的车在路上的模型,将路定义为Abstraction类,车定位为Implementor类(也可以反过来)。对应的UML模型如下:

    这个结构很清晰,方便后续的扩展和维护,如果要添加一种新的类型,只需要添加一个类即可完成。

    3、C++代码

    Road.h

    #include <iostream>
    
    #ifndef __CAR__H__
    #define __CAR__H__
    
    using namespace std;
    
    class AbstractCar {
        public:
            virtual void run () = 0;
    };
    
    class Car:public AbstractCar {
        public:
            void run () override {
                cout<<"Car";
            }
    };
    
    class Bus:public AbstractCar {
        public:
            void run () override {
                cout<<"Bus";
            }
    };
    
    class Moto:public AbstractCar {
        public:
            void run () override {
                cout<<"Moto";
            }
    };
    
    #endif

    Car.h

    #include <iostream>
    #include "Car.h"
    
    #ifndef __ROAD__H__
    #define __ROAD__H__
    
    using namespace std;
    
    class AbstractRoad {
        public:
            AbstractRoad(AbstractCar *car):car(car){}
            virtual void run() = 0;
        protected:
            AbstractCar *car;  // 为了使用多态性,必须使用指针或者引用。
    };
    
    class SpeedWay: public AbstractRoad {
        public:
            SpeedWay(AbstractCar *car):AbstractRoad(car){} // 子类的构造函数调用父类的构造函数来初始父类的成员
            void run() {
                car->run();
                cout<<" run on the speed way"<<endl;
            }
    };
    
    class Street: public AbstractRoad {
        public:
            Street(AbstractCar *car):AbstractRoad(car){}
            void run() {
                car->run();
                cout<<" run on the street"<<endl;
            }
    };
    
    class StateRoad: public AbstractRoad {
        public:
            StateRoad(AbstractCar *car):AbstractRoad(car){}
            void run() {
                car->run();
                cout<<" run on the state road"<<endl;
            }
    };
    
    #endif

    test.cc

    #include "Car.h"
    #include "Road.h"
    
    int main() {
        // 用户选择两个变化维度的组合。
        AbstractRoad *carOnSpeedway     = new SpeedWay(new Car);
        AbstractRoad *busOnSpeedway     = new SpeedWay(new Bus);
        AbstractRoad *motoOnSpeedway    = new SpeedWay(new Moto);
        AbstractRoad *carOnStreet       = new Street(new Car);
        AbstractRoad *busOnStreet       = new Street(new Bus);
        AbstractRoad *motoOnStreet      = new Street(new Moto);
        AbstractRoad *carOnStateRoad    = new StateRoad(new Car);
        AbstractRoad *busOnStateRoad    = new StateRoad(new Bus);
        AbstractRoad *motoOnStateRoad   = new StateRoad(new Moto);
    
        carOnSpeedway     ->run();
        busOnSpeedway     ->run();
        motoOnSpeedway    ->run();
        carOnStreet       ->run();
        busOnStreet       ->run();
        motoOnStreet      ->run();
        carOnStateRoad    ->run();
        busOnStateRoad    ->run();
        motoOnStateRoad   ->run();
    
        return 0;
    }

    输出:

  • 相关阅读:
    VMware虚拟机12安装linux系统
    PHP 底层的运行机制与原理
    分享10条PHP性能优化的小技巧,帮助你更好的用PHP开发
    MySQL wamp密码修改
    分布式之抉择分布式锁
    面试总结——Java高级工程师(三)
    面试总结——Java高级工程师(二)
    面试题总结——走向JAVA高级工程师
    浅谈Nginx之反向代理与负载均衡
    修复TortoiseGit文件夹和文件图标不显示
  • 原文地址:https://www.cnblogs.com/yuandonghua/p/11836249.html
Copyright © 2020-2023  润新知