结构型模式之桥接模式(Bridge Pattern)

定义:

将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

桥接模式 类似于多重继承方案,但是多重继承方案往往违背了类得单一职责原则,其复用性比较差,桥接模式 是比多重继承更好的替代方案。
桥接模式 的核心在于 解耦抽象和实现。

注: 此处的抽象并不是指抽象类或接口这种高层概念,实现也不是继承 或 接口实现 。抽象与实现 其实指的是两种独立变化的维度。其中,抽象包含实现,因此,一个抽象类的变化可能涉及到多种维度的变化导致的。

主要角色:

- 抽象化(Abstraction)角色 :定义抽象类,并包含一个对实现化对象的引用。
- 扩展抽象化(Refined  Abstraction)角色 :是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
- 实现化(Implementor)角色 :定义实现化角色的接口,供扩展抽象化角色调用。
- 具体实现化(Concrete Implementor)角色 :给出实现化角色接口的具体实现。

主要解决

当一个类内部具备两种或多种变化维度时,使用 桥接模式 可以解耦这些变化的维度,使高层代码架构稳定。

优点

抽象和实现分离:这是 桥接模式 的主要特点,也是避免使用 继承 的主要原因。使用 桥接模式,解耦了 抽象 和 实现,使得两者的变化不会对另一方产生影响,使得系统扩展性大大增强。
优秀的扩展能力:桥接模式 的出现就是为了解决多个独立变化的维度的耦合,其高层模块聚合关系已确定(稳定)。因此,无论是 抽象 变化还是 实现 变化,只要对其进行扩展即可,高层代码无需任何更改即可接收扩展。高层代码依赖抽象,严格遵循了 依赖倒置原则。
实现细节对客户透明:由于 桥接模式 在高层模块(抽象层)通过聚合关系构建了稳定的架构(封装)。因此,客户只需与高层模块交互,对 抽象 和 实现 的细节完全不需关注。

缺点

桥接模式 由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程,因此会增加系统的理解与设计难度。

使用场景

  • 一个类存在两个(或多个)独立变化的维度,且这两个维度都需要进行扩展;
  • 不希望或不适合使用继承的场景;
  • 当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。

实例

【例】视频播放器

需要开发一个跨平台视频播放器,可以在不同操作系统平台(如Windows、Mac、Linux等)上播放多种格式的视频文件,常见的视频格式包括RMVB、AVI、WMV等。该播放器包含了两个维度,适合使用桥接模式。

类图
结构型模式之桥接模式(Bridge Pattern)_第1张图片
视频文件接口(实现化角色)

/**
 * @author pzz
 * @date 2022/5/17
 * 视频文件
 * 实现化角色
 */
public interface VideoFile {
    //解码功能
    public void decode(String fileName);
}

avi视频文件(具体的实现化角色)

/**
 * @author pzz
 * @date 2022/5/17
 * avi视频文件
 * 具体的实现化角色
 */
public class AviFile implements VideoFile{
    @Override
    public void decode(String fileName) {
        System.out.println("avi视频文件:"+fileName);
    }
}

rmv视频文件(具体的实现化角色)

/**
 * @author pzz
 * @date 2022/5/17
 * rmv视频文件
 * 具体的实现化角色
 */
public class RmvbFile implements VideoFile{
    @Override
    public void decode(String fileName) {
        System.out.println("rmv视频文件:"+fileName);
    }
}

抽象的操作系统类(抽象化角色)

/**
 * @author pzz
 * @date 2022/5/17
 * 抽象的操作系统类
 * 抽象化角色
 */
public abstract class OpratingSystem {
    //声明视频对象
    protected VideoFile videoFile;

    public OpratingSystem(VideoFile videoFile) {
        this.videoFile = videoFile;
    }

    public abstract void play(String fileName);
}

Mac操作系统(扩展抽象化角色)

/**
 * @author pzz
 * @date 2022/5/17
 * mac操作系统
 * 扩展抽象化角色
 */
public class Mac extends OpratingSystem{
    public Mac(VideoFile videoFile) {
        super(videoFile);
    }

    @Override
    public void play(String fileName) {
        videoFile.decode(fileName);
    }
}

Windows操作系统(扩展抽象化角色)

/**
 * @author pzz
 * @date 2022/5/17
 * Windows操作系统
 * 扩展抽象化角色
 */
public class Windows extends OpratingSystem{

    public Windows(VideoFile videoFile) {
        super(videoFile);
    }

    @Override
    public void play(String fileName) {
        videoFile.decode(fileName);
    }
}

测试类

/**
 * @author pzz
 * @date 2022/5/17
 * 测试类
 */
public class Client {
    public static void main(String[] args) {
        //创建mac系统对象
        OpratingSystem system = new Mac(new AviFile());
        //使用操作系统播放视频文件
        system.play("夏洛特烦恼");
    }
}

测试结果
结构型模式之桥接模式(Bridge Pattern)_第2张图片

解释说明:

操作系统和视频文件这是两个维度,当你需要时,可以独立扩展,不会影响原来的代码。

好处:

  • 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。

    如:如果现在还有一种视频文件类型wmv,我们只需要再定义一个类实现VideoFile接口即可,其他类不需要发生变化。

  • 实现细节对客户透明

适配器模式和桥接模式的异同:

共同点:桥接和适配器都是让两个东西配合工作。

不同点:出发点不同。

  • 适配器:改变已有的两个接口,让他们相容。
  • 桥接模式:分离抽象化和实现,使两者的接口可以不同,目的是分离。

所以说,如果你拿到两个已有模块,想让他们同时工作,那么你使用的适配器。
如果你还什么都没有,但是想分开实现,那么桥接是一个选择。

装饰模式和桥接模式的区别:

两个模式都是为了解决子类过多问题, 但他们的诱因不同:

  • 桥接模式对象自身有 沿着多个维度变化的趋势 , 本身不稳定,设计之初就应该使用。
  • 装饰模式是适应新需求而添加新功能,并且不影响其他对象的一种模式,在扩展时使用。

结束!


				当你认为这样是对的,你就应该坚持下去。

你可能感兴趣的:(设计模式,桥接模式,java,开发语言)