桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

假如你有一个几何形状(Shape)类, 从它能扩展出两个子类: 圆形(Circle)和方形(Square)。你希望对这样的类层次结构进行扩展以使其包含颜色, 所以你打算创建名为红色(Red)和蓝色(Blue)的形状子类。但是,由于你已有两个子类,所以总共需要创建四个类才能覆盖所有组合,例如蓝色圆形(BlueCircle)和红色方形(RedSquare)。
在层次结构中新增形状和颜色将导致代码复杂程度指数增长。例如添加三角形状,你需要新增两个子类,也就是每种颜色一个;此后新增一种新颜色需要新增三个子类,即每种形状一个。如此以往,情况会越来越糟糕。
解决办法:
问题的根本原因是我们试图在两个独立的维度——形状与颜色——上扩展形状类。这在处理类继承时是很常见的问题。
桥接模式通过将继承改为组合的方式来解决这个问题。具体来说,就是抽取其中一个维度并使之成为独立的类层次,这样就可以在初始类中引用这个新层次的对象,从而使得一个类不必拥有所有的状态和行为。

根据该方法,我们可以将颜色相关的代码抽取到拥有红色和蓝色两个子类的颜色类中,然后在形状类中添加一个指向某一颜色对象的引用成员变量。现在,形状类可以将所有与颜色相关的工作委派给连入的颜色对象。这样的引用就成为了形状和颜色之间的桥梁。此后,新增颜色将不再需要修改形状的类层次,反之亦然。

优点

  • 抽象与实现分离,扩展能力强
  • 符合开闭原则
  • 符合合成复用原则
  • 其实现细节对客户透明
  • 缺点

    由于聚合关系建立在抽象层,要求开发者针对抽象化进行设计与编程,能正确地识别出系统中两个独立变化的维度,这增加了系统的理解与设计难度。

    结构


    桥接(Bridge)模式包含以下主要角色。

  • 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。提供高层控制逻辑, 依赖于完成底层实际工作的实现对象。
  • 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
  • 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
  • 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
  • 客户端(Client):仅关心如何与抽象部分合作。但是,客户端需要将抽象对象与一个实现对象连接起来。
  • 适用场景

    1. 当一个对象有多个变化因素的时候,考虑依赖于抽象的实现,而不是具体的实现。如手机品牌有2种变化因素,一个是品牌,一个是功能。
    2. 当多个变化因素在多个对象间共享时,考虑将这部分变化的部分抽象出来再聚合/合成进来,如通讯录和游戏,其实是可以共享的。
    3. 当我们考虑一个对象的多个变化因素可以动态变化的时候,考虑使用桥接模式,如上面例子中的手机品牌是变化的,手机的功能也是变化的,所以将他们分离出来,独立的变化。

    实现

    1. 明确类中独立的维度。独立的概念可能是:抽象/平台,域/基础设施,前端/后端或接口/实现。
    2. 了解客户端的业务需求,并在抽象基类中定义它们。
    3. 确定在所有平台上都可执行的业务。并在通用实现接口中声明抽象部分所需的业务。
    4. 为你域内的所有平台创建实现类,但需确保它们遵循实现部分的接口。
    5. 在抽象类中添加指向实现类型的引用成员变量。抽象部分会将大部分工作委派给该成员变量所指向的实现对象。
    6. 如果你的高层逻辑有多个变体,则可通过扩展抽象基类为个变体创建一个精确抽象。
    7. 客户端代码必须将实现对象传递给抽象部分的构造函数才能使其能够相互关联。此后,客户端只需与抽象对象进行交互,无需和实现对象打交道。

    示例1

    现需要提供大中小3种型号的画笔,能够绘制5种不同颜色,如果使用蜡笔,我们需要准备3*5=15支蜡笔,也就是说必须准备15个具体的蜡笔类。而如果使用毛笔的话,只需要3种型号的毛笔,外加5个颜料盒,用3+5=8个类就可以实现15支蜡笔的功能。
    实际上,蜡笔和毛笔的关键一个区别就在于笔和颜色是否能够分离。即将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立地变化"。关键就在于能否脱耦。蜡笔的颜色和蜡笔本身是分不开的,所以就造成必须使用15支色彩、大小各异的蜡笔来绘制图画。而毛笔与颜料能够很好的脱耦,各自独立变化,便简化了操作。在这里,抽象层面的概念是:“毛笔用颜料作画”,而在实现时,毛笔有大中小三号,颜料有红绿蓝黑白等5种,于是便可出现3×5种组合。每个参与者(毛笔与颜料)都可以在自己的自由度上随意转换。蜡笔由于无法将笔与颜色分离,造成笔与颜色两个自由度无法单独变化,使得只有创建15种对象才能完成任务。

    #include <iostream>
    #include <string>
     
    //实现类接口Color(颜色类)
    class Color 
    {
    public:
    	virtual void bepaint(const std::string&, const std::string&) = 0;
    };
     
    //具体实现类Red
    class Red : public Color {
    public:
    	void bepaint(const std::string& penType, const std::string& name) 
    	{
    		std::cout << penType + "红色的" + name + "." << std::endl;
    	}
    };
     
    //具体实现类Green
    class Green : public Color {
    public:
    	void bepaint(const std::string& penType, const std::string& name) 
    	{
    		std::cout << penType + "绿色的" + name + "." << std::endl;
    	}
    };
     
    //抽象类Pen
    class Pen {
    public:
    	virtual void draw(const std::string& name) = 0;
    	void setColor(Color* color) 
    	{
    		this->color = color;
    	}
    protected:
    	Color* color;
    };
     
    //扩充抽象类BigPen
    class BigPen : public Pen {
    public:
    	void draw(const std::string& name) {
    		std::string penType = "大号毛笔绘制";
    		this->color->bepaint(penType, name);
    	}
    };
     
    //扩充抽象类SmallPen
    class SmallPen : public Pen {
    public:
    	void draw(const std::string& name) {
    		std::string penType = "小号毛笔绘制";
    		this->color->bepaint(penType, name);
    	}
    };
     
    //客户端测试类
    int main(void) {
    	Color* color;
    	Pen* pen;
     
    	//这里假装用反射获取 
    	color = (Color*) new Green();
    	pen = (Pen*) new SmallPen();
     
    	pen->setColor(color);
    	pen->draw("圣诞树");
     
    	delete color;
    	delete pen;
     
    	return 0;
    }
    

    示例2

    Abstraction.h:

    // Abstraction.h:
    #ifndef ABSTRACTION_H_
    #define ABSTRACTION_H_
    
    #include <string>
    #include "Implementation.h"
    
    // 抽象类: Pen
    class Pen {
     public:
        virtual void draw(std::string name) = 0;
        void set_color(Color* color) {
            color_ = color;
        }
    
     protected:
        Color* color_;
    };
    
    #endif  // ABSTRACTION_H_
    

    RefinedAbstraction.h:

    #ifndef REFINED_ABSTRACTION_H_
    #define REFINED_ABSTRACTION_H_
    
    #include <string>
    #include "Abstraction.h"
    
    // 精确抽象类: BigPen
    class BigPen : public Pen {
     public:
        void draw(std::string name) {
            std::string pen_type = "大号钢笔绘制";
            color_->bepaint(pen_type, name);
        }
    };
    
    // 精确抽象类: SmallPencil
    class SmallPencil : public Pen {
     public:
        void draw(std::string name) {
            std::string pen_type = "小号铅笔绘制";
            color_->bepaint(pen_type, name);
        }
    };
    
    #endif  // REFINED_ABSTRACTION_H_
    

    Implementation.h:

    #ifndef IMPLEMENTATION_H_
    #define IMPLEMENTATION_H_
    
    #include <string>
    #include <iostream>
    
    // 实现类接口: 颜色
    class Color {
     public:
        virtual void bepaint(std::string pen_type, std::string name) = 0;
    };
    
    #endif  // IMPLEMENTATION_H_
    

    ConcreteImplementation.h:

    #ifndef CONCRETE_IMPLEMENTATION_H_
    #define CONCRETE_IMPLEMENTATION_H_
    
    #include <string>
    #include "Implementation.h"
    
    // 具体实现类: Red
    class Red : public Color {
     public:
        void bepaint(std::string pen_type, std::string name) override {
            std::cout << pen_type << "红色的" << name << "." << std::endl;
        }
    };
    
    // 具体实现类: Green
    class Green : public Color {
     public:
        void bepaint(std::string pen_type, std::string name) override {
            std::cout << pen_type << "绿色的" << name << "." << std::endl;
        }
    };
    
    
    #endif  // CONCRETE_IMPLEMENTATION_H_
    

    main.cpp:

    #include "ConcreteImplementation.h"
    #include "RefinedAbstraction.h"
    
    int main() {
        // 客户端根据运行时参数获取对应的Color和Pen
        Color* color = new Red();
        Pen* pen = new SmallPencil();
    
        pen->set_color(color);
        pen->draw("太阳");
    
        delete color;
        delete pen;
    }
    

    运行结果:

    $g++ -g main.cpp -o bridge -std=c++11
    $./bridge 
    小号铅笔绘制红色的太阳.
    

    示例3

    用Python实现

    # 抽象规格类
    class Size(object):
     
        def __init__(self, size):
            self.color = None
            self._size = size
     
        # match_color 作为桥接, 各自的变化, 不影响其他分类
        def match_color(self, color):
            self.color = color
     
        def produce(self):
            print(f"生产 规格为: {self._size} 颜色为: {self.color.color()} 的笔")
     
     
    # 大号规格,具体规格类,继承抽象规格类
    class BigSize(Size):
     
        def __init__(self):
            super(BigSize, self).__init__('大号')
     
     
    # 中号
    class MiddleSize(Size):
     
        def __init__(self):
            super(MiddleSize, self).__init__('中号')
     
     
    # 小号
    class SmallSize(Size):
     
        def __init__(self):
            super(SmallSize, self).__init__('小号')
     
     
    # 抽象颜色类
    class Color(object):
     
        def __init__(self, color):
            self._color = color
     
        def color(self):
            return self._color
     
     
    # 红色
    class RedColor(Color):
     
        def __init__(self):
            super(RedColor, self).__init__('红色')
     
     
    # 蓝色
    class BlueColor(Color):
     
        def __init__(self):
            super(BlueColor, self).__init__('蓝色')
     
     
    # 黄色
    class YellowColor(Color):
     
        def __init__(self):
            super(YellowColor, self).__init__('黄色')
     
     
    if __name__ == "__main__":
        red = RedColor()
        blue = BlueColor()
        yellow = YellowColor()
     
        big_size = BigSize()
        big_size.match_color(red)
        big_size.produce()
        big_size.match_color(blue)
        big_size.produce()
        big_size.match_color(yellow)
        big_size.produce()
     
        middle_size = MiddleSize()
        middle_size.match_color(red)
        middle_size.produce()
        middle_size.match_color(blue)
        middle_size.produce()
        middle_size.match_color(yellow)
        middle_size.produce()
     
        small_size = SmallSize()
        small_size.match_color(blue)
        small_size.produce()
        small_size.match_color(red)
        small_size.produce()
        small_size.match_color(yellow)
        small_size.produce()
    

    示例4

    #抽象类:人
    class people:
        def set_skill(self,skill):
            self.skill=skill
        def perform_skill(self):
            pass
     
    #具体抽象类:花匠
    class hua_j(people):
        def perform_skill(self):
            print('我是花匠')
            self.skill.perform_skill()
    #具体抽象类:木匠
    class mu_j(people):
        def perform_skill(self):
            print('我是木匠')
            self.skill.perform_skill()
    #具体抽象类:铁匠
    class tie_j(people):
        def perform_skill(self):
            print('我是铁匠')
            self.skill.perform_skill()
         
     
    #功能类,也是实现类
    class  skill:
        def perform_skill(self):
            pass
         
    #具体功能类,也是具体实现类 种花
    class  skill_hua(skill):
        def perform_skill(self):
            print('我会种花')
         
    #具体功能类,也是具体实现类 做木桌子
    class  skill_mu:
        def perform_skill(self):
            print('我会做木桌子')
     
    #具体功能类,也是具体实现类 做铁桌子
    class  skill_tie:
        def perform_skill(self):
            print('我会做铁桌子')
     
    #具体功能类,也是具体实现类 做老师
    class  skill_teacher:
        def perform_skill(self):
            print('我会做老师,可以教学生')
    #具体功能类,也是具体实现类 做家具
    class  skill_jj:
        def perform_skill(self):
            print('我会做家具')
     
    def main():
        h=hua_j() #花匠
        m=mu_j() #木匠
        t=tie_j() #铁匠
     
        sh=skill_hua()# 本事:会种花
        sm=skill_mu() #本事:会做木头桌子
        st=skill_tie() #本事:会做铁桌子
        s_t=skill_teacher() #本事:会教学生
        s_jj=skill_jj() #本事:会做家具
     
        h.set_skill(sh) #给花匠set种花的本事
        h.perform_skill() #花匠 种花
        h.set_skill(s_t) #给花匠set做老师的本事
        h.perform_skill() #花匠教学生
     
        print('=============')
        m.set_skill(sm) #给木匠set 做木桌子的本事
        m.perform_skill() #木匠 做木桌子
        m.set_skill(s_t) #给木匠set做老师的本事
        m.perform_skill() #木匠教学生
        m.set_skill(s_jj) #给木匠set做家具的本事
        m.perform_skill() #木匠做家具
     
        print('=============')
        t.set_skill(st) #给木匠set 做木桌子的本事
        t.perform_skill() #木匠 做木桌子
        t.set_skill(s_t) #给木匠set做老师的本事
        t.perform_skill() #木匠教学生
        t.set_skill(s_jj) #给木匠set做家具的本事
        t.perform_skill() #木匠做家具
     
     
    if __name__ == '__main__':
        main()
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » 桥接模式(桥接)

    发表评论