Java设计模式-桥接模式 理论代码相结合

语言: CN / TW / HK

highlight: a11y-dark theme: cyanosis


这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战

继Java设计模式-装饰器模式后的桥接模式出来了,感兴趣的话,就来看一看吧。

会了就当复习丫,不会来一起来看看吧。

很喜欢一句话:“八小时内谋生活,八小时外谋发展”

如果你也喜欢,让我们一起坚持吧!!

共勉😁

校园一角

设计模式系列

一、桥接模式介绍

1)引入

​ 在现实生活中,某些类具有两个或多个维度的变化,如图形既可按形状分,又可按颜色分。如何设计类似于 Photoshop 这样的软件,能画不同形状和不同颜色的图形呢?如果用继承方式,m 种形状和 n 种颜色的图形就有 m×n 种,不但对应的子类很多,而且扩展困难。

​ 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。(当然并不局限于桥接模式)

2)概述

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

桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量

将抽象部分与他的实现部分分离这句话不是很好理解,其实这并不是将抽象类与他的派生类分离,而是抽象类和它的派生类用来实现自己的对象。这样还是不能理解的话。我们就先来认清什么是抽象化,什么是实现化,什么是脱耦

抽象化:存在于多个实体中的共同的概念性联系,就是抽象化。作为一个过程,抽象化就是忽略一些信息,从而把不同的实体当做同样的实体对待。

实现化:抽象化给出的具体实现,就是实现化

脱耦:所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称脱耦。在这里,脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联。

两个角色之间的继承关系改为聚合关系,就是将它们之间的强关联改换成为弱关联。因此,桥梁模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用组合/聚合关系而不是继承关系,从而使两者可以相对独立地变化。这就是桥梁模式的用意。

3)模式结构

桥接模式的结构图

由抽象化角色和修正抽象化角色组成的抽象化等级结构。

由实现化角色和两个具体实现化角色所组成的实现化等级结构。

抽象化 (Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。

扩展抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。

实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。

具体实现化(Concrete Implementor)角色:这个角色给出实现化角色接口的具体实现。

4)使用场景

  • 不希望或不适用使用继承的场景
  • 接口或抽象类不稳定的场景
  • 重用性要求较高的场景

二、桥接模式案例

2.1、案例

下面我们举一个例子:

需要开发一个跨平台视频播放器,可以在不同操作系统平台(如Windows、Mac、Linux等)上播放多种格式的视频文件,常见的视频格式包括RMVB、AVI、WMV等。

该播放器包含了两个维度,适合使用桥接模式。桥接模式的核心意图就是把这些实现独立出来,让它们各自地变化,这就使得每种实现的变化不会影响其他实现,从而达到应对变化的目的。

图解:

在这里插入图片描述

从上面这个图可以看出,

两个维度分别为:

  1. OperatingSystem就是抽象化角色,Windows和Mac是扩展化角色,
  2. VideoFile就是实现化角色,AVIFile和RMVBFile是具体实现化角色。

我都懂的,还是看下面👇代码的实现是咋样的吧😁

2.2、代码实现

OperatingSystem:

```java public abstract class OperatingSystemVersion {

protected VideoFile videoFile;

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

public abstract void play(String fileName);

} ```

Windows和Mac是扩展化角色

```java public class Windows extends OperatingSystemVersion {

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

public void play(String fileName) {
    System.out.println("Windows正在播放:");
    videoFile.decode(fileName);
}

}

public class Mac extends OperatingSystemVersion {

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

@Override
public void play(String fileName) {
    System.out.println("Mac正在播放:");
    videoFile.decode(fileName);
}

} ```

VideoFile

java public interface VideoFile { void decode(String fileName); }

AVIFile和RMVBFile是具体实现化角色

```java public class REVBBFile implements VideoFile {

public void decode(String fileName) {
    System.out.println("rmvb文件:" + fileName);
}

}

public class AVIFile implements VideoFile { @Override public void decode(String fileName) { System.out.println("avi视频文件:"+ fileName); } } ```

测试:

java public class Client { public static void main(String[] args) { OperatingSystemVersion os = new Mac(new AVIFile()); os.play("战狼3"); /** * 输出:Mac正在播放:avi视频文件:战狼3 */ } }

这么写之后,无论是对于扩展OperatingSystem还是VideoFile方面,都可以独立的扩展,非常的方便。也符合上👆文中对于桥接模式的定义:将抽象部分与实现部分分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度

三、总结

优缺点:

桥接(Bridge)模式的优点是:

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

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

注意事项

  • 不要一涉及继承就考虑该模式,尽可能把变化的因素封装到最细、最小的逻辑单元中,避免风险扩散
  • 当发现类的继承有n层时,可以考虑使用该模式

四、自言自语

你卷我卷,大家卷,什么时候这条路才是个头啊。😇(还是直接上天吧)

有时候也想停下来歇一歇,一直做一个事情,感觉挺难坚持的。😁

你好,如果你正巧看到这篇文章,并且觉得对你有益的话,就给个赞吧,让我感受一下分享的喜悦吧,蟹蟹。🤗

如若有写的有误的地方,也请大家不啬赐教!!

同样如若有存在疑惑的地方,请留言或私信,定会在第一时间回复你。

持续更新中