桥接设计模式

1、手机操作问题

现在对不同手机类型的不同品牌实现操作编程(比如:开机、关机、上网,打电话等)

image-20230507223059095

【1】以上传统方式的缺点

1)扩展性问题(类爆炸),如果我们再增加手机样式(旋转式),就需要增加各个品牌手机的类,同样如果我们增加一个手机品牌,也要再各个手机样式类下增加。

2)违反了单一职责原则,当我们增加手机样式时,要同时增加所有品牌的手机,这样增加了代码维护成本。

3)解决方案-使用桥接模式。


2、桥接模式的结构

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

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

3、桥接模式——基本介绍

1)桥接模式(Bridge模式)是指:将实现与抽象放在两个不同的类层次中,使两个层次可以独立改变。它是使用组合关系代理继承关系来实现,从而降低了抽象和实现这两个可变维度。

2)是一种结构型设计模式

3)Bridge模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象(Abstraction)与行为实现(Implementation)分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// 接口
public interface Brand {
void open();
void close();
void call();
}

public class XiaoMi implements Brand {
@Override
public void open() {
System.out.println(" 小米手机开机");
}

@Override
public void close() {
System.out.println(" 小米手机关机");
}

@Override
public void call() {
System.out.println(" 小米手机打电话");
}
}

public class Vivo implements Brand {
@Override
public void open() {
System.out.println(" Vivo手机开机");
}

@Override
public void close() {
System.out.println(" Vivo手机关机");
}

@Override
public void call() {
System.out.println(" Vivo手机打电话");
}
}

public abstract class Phone {
// 组合品牌
private Brand brand;

// 构造器
public Phone(Brand brand) {
this.brand = brand;
}

protected void open() {
this.brand.open();
}
protected void close() {
this.brand.close();
}
protected void call() {
this.brand.call();
}
}

public class FoldedPhone extends Phone {
// 构造器
public FoldedPhone(Brand brand) {
super(brand);
}
public void open() {
super.open();
System.out.println(" 折叠样式手机 ");
}
public void close() {
super.close();
System.out.println(" 折叠样式手机 ");
}
public void call() {
super.call();
System.out.println(" 折叠样式手机 ");
}
}

4)视频播放器案例

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

image-20230626104428991

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 抽象的操作系统(抽象化角色)
public abstract class OperatingSystem {
protected VideoFile videoFile;

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

public abstract void play(String fileName);
}

// windows操作系统(扩展抽象化角色)
public class Windows extends OperatingSystem {
public Windows(VideoFile videoFile) {
super(videoFile);
}

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

// Mac操作系统(扩展抽象化角色)
public class Mac extends OperatingSystem {
public Mac(VideoFile videoFile) {
super(videoFile);
}

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

// 视频文件(实现化角色)
public interface VideoFile {
void decode(String name);
}

// avi视频文件(具体的实现化角色)
public class AVIFile implements VideoFile {
@Override
public void decode(String name) {
System.out.println("avi视频文件:" + name);
}
}

// rmvb视频文件(具体的实现化角色)
public class RMVBFile implements VideoFile {
@Override
public void decode(String name) {
System.out.println("rmvb视频文件:" + name);
}
}

4、桥接模式在JDBC中剖析

1)JDBC的Driver接口,如果从桥接模式来看,Driver就是一个接口,下面可以有MySQL的Driver,Oracle的Driver,这些就都可以当作实现接口类。

2)代码分析


4、桥接模式的注意事项及应用场景

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

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

  • 实现细节对客户透明。

【2】注意事项

1)实现了抽象和实现部分的分离,从而极大的提高了系统的灵活性,让抽象部分和实现部分独立开来,这有助于系统进行分层设计,从而产生更好的结构化系统。

2)对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了,其他的部分由具体业务来完成。

3)桥接模式替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本。

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

5)桥接模式要求正确识别出系统中两个独立变化的维度(抽象和实现),因此其使用范围有一定的局限性,即需要有这样的应用场景。

6)装饰者模式是主体与附加功能的解耦,桥接是抽象与具体的解耦。

【3】应用场景

1)对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。

2)当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时。

3)当一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性时。避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。

4)常见的应用场景:

— JDBC驱动程序

— 银行转账系统

— — 转账分类:网上转账,柜台转账,ATM转账

— — 转账用户类型:普通用户,银卡用户,金卡用户

— 消息管理

— — 消息类型:即时消息,延时消息

— — 消息分类:手机短信,邮件消息,QQ消息…