• 【设计模式深度剖析】【5】【结构型】【桥接模式】| 以电视和遥控器为例加深理解


    👈️上一篇:组合模式    |   下一篇:外观模式👉️

    设计模式-专栏👈️

    桥接模式(Bridge Pattern)

    ==>本文示例源码,点击查看<==

    定义

    英文原话是:

    • Bridge Pattern is a software design pattern that is used to overcome the limitations of the traditional inheritance.
    • It decouples an abstraction from its implementation so that the two can vary independently.
    • The bridge pattern consists of two parts: abstraction and implementation.
    • The abstraction part defines the interface that the client uses to interact with the system.
    • The implementation part implements the abstraction by providing the functionality required by the client.

    直译

    • 桥接模式是一种用于克服传统继承局限性的软件设计模式。
    • 它将抽象部分与实现部分解耦,使得两者可以独立地变化
    • 桥接模式由两部分组成:抽象部分和实现部分。
      • 抽象部分定义了客户端与系统交互的接口。
      • 实现部分通过提供客户端所需的功能来实现抽象部分。

    理解

    桥接模式(Bridge Pattern)从字面上理解,可以想象成一个桥梁连接了两个不同的部分,使得这两个部分可以相互通信或协作,而不需要彼此之间有直接的依赖关系。在软件设计中,这两个部分通常指的是抽象部分和实现部分。

    在桥接模式中,抽象部分定义了一个接口(或抽象类),用于定义抽象层的行为。实现部分则实现了这个接口,提供了具体实现。这两个部分通过组合的方式关联在一起,而不是继承。这样做的好处是,抽象部分和实现部分可以独立变化,只要它们遵循相同的接口规范。

    桥接模式的主要目的是通过组合的方式建立抽象与实现之间的联系,而不是通过继承。

    这允许开发人员在不修改抽象接口的情况下修改实现,从而提高了系统的灵活性和可扩展性。

    同时,桥接模式也避免了多重继承可能带来的问题,如违背类的单一职责原则和降低复用性等。

    4个角色

    桥接模式(Bridge Pattern)是一种结构型设计模式,它将抽象部分与它的实现部分分离,使得它们可以独立地变化。这种类型的设计模式属于结构型模式,它通过提供抽象层和实现层之间的桥接结构,来实现二者的解耦。

    UML类图

    在这里插入图片描述

    桥接模式包含以下四个角色:

    1. 抽象化(Abstraction)角色:定义抽象类的接口,并保存一个对实现化对象的引用。
    2. 扩展抽象化(RefinedAbstraction)角色:抽象化角色的子类,实现它要求的业务逻辑,并通过组合关系调用实现化角色中的业务方法。
    3. 实现化(Implementor)角色:这个接口定义了实现化角色的接口,但不提供具体的实现。这个接口必须被实现化角色的具体类来实现。
    4. 具体实现化(ConcreteImplementor)角色:实现化角色接口的具体实现类。

    代码示例

    以下是一个Java示例来演示桥接模式:

    package com.polaris.designpattern.list2.structural.pattern5.bridge.classicdemo;
    
    // 实现化角色接口
    interface Implementor {  
        void operationImpl();  
    }  
      
    // 具体实现化角色  
    class ConcreteImplementorA implements Implementor {  
        @Override  
        public void operationImpl() {  
            System.out.println("操作A的实现");  
        }  
    }  
      
    class ConcreteImplementorB implements Implementor {  
        @Override  
        public void operationImpl() {  
            System.out.println("操作B的实现");  
        }  
    }  
      
    // 抽象化角色  
    abstract class Abstraction {  
        protected Implementor implementor;  
      
        public Abstraction(Implementor implementor) {  
            this.implementor = implementor;  
        }  
      
        public abstract void operation();  
    }  
      
    // 扩展抽象化角色  
    class RefinedAbstraction extends Abstraction {  
        public RefinedAbstraction(Implementor implementor) {  
            super(implementor);  
        }  
      
        @Override  
        public void operation() {  
            // 在调用实现化角色的方法之前或之后,可以添加一些逻辑  
            System.out.println("扩展操作前...");  
            implementor.operationImpl();  
            System.out.println("扩展操作后...");  
        }  
    }  
      
    // 客户端代码  
    public class BridgePatternDemo {  
        public static void main(String[] args) {  
            Implementor implementorA = new ConcreteImplementorA();  
            Abstraction abstraction = new RefinedAbstraction(implementorA);  
            abstraction.operation();
    
            System.out.println("-----------");
    
            Implementor implementorB = new ConcreteImplementorB();  
            abstraction = new RefinedAbstraction(implementorB);  
            abstraction.operation();  
        }  
    }
    
    /* Output:
    扩展操作前...
    操作A的实现
    扩展操作后...
    -----------
    扩展操作前...
    操作B的实现
    扩展操作后...
    *///~
    

    在这个例子中,Implementor 是实现化角色接口,ConcreteImplementorAConcreteImplementorB 是两个具体实现化角色。Abstraction 是抽象化角色,它持有一个对实现化角色的引用,而 RefinedAbstraction 是扩展抽象化角色,它扩展了 Abstraction 的功能。客户端代码通过组合关系,将实现化角色和抽象化角色组合在一起,实现了二者的解耦。

    应用

    再来总结下,桥接模式(Bridge Pattern)是一种结构型设计模式,它通过将抽象部分与实现部分解耦,使得它们可以独立地变化。

    桥接模式通常用于以下情况:

    1. 抽象和实现需要独立变化:当抽象部分和实现部分都需要独立扩展时,可以使用桥接模式。例如,不同的数据库系统(抽象部分)可能需要不同的驱动程序(实现部分)。
    2. 需要跨多个平台实现:当系统需要在不同的平台上运行时,可以使用桥接模式来封装平台相关的代码。
    3. 避免继承层次过深:当使用继承来实现多个维度的变化时,可能会导致继承层次过深,使得代码难以理解和维护。桥接模式通过组合代替继承,可以解决这个问题。

    优点

    1. 分离抽象与实现:桥接模式将抽象部分与实现部分分离,使得它们可以独立地变化。这增加了系统的灵活性和可扩展性。
    2. 减少继承层次:通过组合关系替代继承关系,减少了继承层次,降低了系统的复杂度。
    3. 支持动态切换实现:在运行时,可以动态地切换实现部分,而不需要修改抽象部分的代码。
    4. 符合开闭原则:桥接模式符合开闭原则,即对扩展开放,对修改封闭。当需要添加新的实现时,只需要添加新的实现类,而不需要修改已有的代码。

    缺点

    1. 增加了系统的复杂性:由于引入了抽象部分和实现部分两个层次,增加了系统的复杂性。对于简单的系统来说,可能不需要使用桥接模式。
    2. 可能增加了系统开销:在运行时,需要维护抽象部分和实现部分之间的关联关系,这可能会增加一些额外的开销。

    使用场景

    以下是一些适合使用桥接模式的场景:

    1. 多种操作系统:当软件需要在多种操作系统上运行时,可以使用桥接模式来封装与操作系统相关的代码。这样,只需要编写一次抽象部分的代码,就可以通过更换不同的实现部分来适应不同的操作系统。
    2. 多种数据库系统:当软件需要与多种数据库系统进行交互时,可以使用桥接模式来封装与数据库相关的代码。这样,只需要编写一次抽象部分的代码,就可以通过更换不同的实现部分来适应不同的数据库系统。
    3. 多种图形用户界面:当软件需要支持多种图形用户界面(如Windows、Mac、Linux等)时,可以使用桥接模式来封装与界面相关的代码。这样,只需要编写一次抽象部分的代码,就可以通过更换不同的实现部分来适应不同的界面风格。
    4. 多种网络协议:当软件需要与多种网络协议进行通信时,可以使用桥接模式来封装与网络协议相关的代码。这样,只需要编写一次抽象部分的代码,就可以通过更换不同的实现部分来适应不同的网络协议。

    示例解析:电视和遥控器

    ==>本文示例源码,点击查看<==

    在生活中,一个常见的桥接模式的例子是电视和遥控器。

    电视(抽象化角色)提供了观看节目的基本功能,而遥控器(实现化角色)则负责控制电视的不同操作(如换台、调节音量等)。

    电视本身不关心遥控器是如何实现的,只要它符合一定的接口规范(如红外信号、蓝牙等)。

    同样,遥控器也可以控制不同类型的电视,只要电视也符合相应的接口规范。

    UML类图

    在这里插入图片描述

    下面是一个简化的代码示例,用于说明这个场景:

    package com.polaris.designpattern.list2.structural.pattern5.bridge.remotecontroldemo;
    
    //遥控器接口(Implementor)
    interface RemoteControl {
        //换台
        void changeChannel(int channel);
    
        //调节音量
        void adjustVolume(int volume);
        // ... 其他控制方法  
    }
    
    //具体遥控器(ConcreteImplementor)  
    class InfraredRemoteControl implements RemoteControl {
        @Override
        public void changeChannel(int channel) {
            System.out.println("使用红外遥控器换台到: " + channel);
        }
    
        @Override
        public void adjustVolume(int volume) {
            System.out.println("使用红外遥控器调节音量到: " + volume);
        }
        // ... 实现其他控制方法  
    }
    
    //电视抽象类(Abstraction) 
    abstract class Television {
        protected RemoteControl remoteControl;
    
        public Television(RemoteControl remoteControl) {
            this.remoteControl = remoteControl;
        }
    
        public abstract void turnOn();
    
        public abstract void turnOff();
    
        // 使用遥控器来控制电视  
        public void watch() {
            System.out.println("正在看电视...");
            remoteControl.changeChannel(10); // 假设切换到10频道  
            remoteControl.adjustVolume(50); // 假设调节音量到50  
        }
    }
    
    //具体电视类(RefinedAbstraction) 
    class LEDTelevision extends Television {
        public LEDTelevision(RemoteControl remoteControl) {
            super(remoteControl);
        }
    
        @Override
        public void turnOn() {
            System.out.println("LED电视已打开");
        }
    
        @Override
        public void turnOff() {
            System.out.println("LED电视已关闭");
        }
    }
    
    //客户端代码  
    public class BridgePatternDemo {
        public static void main(String[] args) {
            // 创建一个红外遥控器  
            RemoteControl infraredRemote = new InfraredRemoteControl();
            // 创建一个LED电视,并使用红外遥控器  
            Television ledTv = new LEDTelevision(infraredRemote);
    
            ledTv.turnOn(); // 打开电视  
            ledTv.watch(); // 使用遥控器观看电视  
            ledTv.turnOff(); // 关闭电视  
        }
    }
    
    /* Output:
    LED电视已打开
    正在看电视...
    使用红外遥控器换台到: 10
    使用红外遥控器调节音量到: 50
    LED电视已关闭
    *///~
    

    在这个例子中,Television 是抽象化角色,它定义了电视的基本操作(如打开、关闭),并持有对 RemoteControl(遥控器)的引用。LEDTelevision 是扩展抽象化角色,它扩展了电视的基本功能,并提供了具体的实现。RemoteControl 是实现化角色接口,定义了遥控器需要实现的方法。InfraredRemoteControl 是具体实现化角色,它实现了红外遥控器的功能。

    客户端代码创建了一个 InfraredRemoteControl 对象和一个 LEDTelevision 对象,并将遥控器对象传递给电视对象。这样,电视就可以通过遥控器来控制自己的行为了。

    这个例子展示了桥接模式如何使得抽象化角色(电视)和实现化角色(遥控器)可以独立地变化。


    👈️上一篇:组合模式    |   下一篇:外观模式👉️

    设计模式-专栏👈️

  • 相关阅读:
    有限元学习笔记-传热及流体力学问题
    这不会又是一个Go的BUG吧?
    Docker 必知必会4----容器之间的通信
    Charles抓包工具的基本操作
    ABBYY15切换中文版教程及离线下载安装教程
    在 Net7.0环境下通过反射创建对象和调用方法
    linux中qt编写串口程序,linux下基于QT的串口程序
    ElasticSearch 批量插入漏数据
    Docker中安装并配置redis
    IllegalStateException: FragmentManager is already executing transactions
  • 原文地址:https://blog.csdn.net/qq_28727015/article/details/139250923