桥接模式
# 桥接模式
桥接模式的关键思想是通过组合而不是继承来实现抽象和实现的关联,使得两者能够独立地变化。这种解耦允许系统在运行时动态地选择具体的实现,从而提供更大的灵活性和可扩展性。
# 定义
桥接模式(Bridge Pattern)是一种结构型设计模式,它的主要目的是将抽象部分与实现部分分离,使它们可以独立变化。桥接模式通过组合的方式将抽象和实现关联起来,从而实现了两者的解耦。
# 结构
抽象类(Abstraction):定义了抽象部分的接口,维护一个指向实现部分的引用。
扩展抽象类(RefinedAbstraction):对抽象部分进行扩展,实现更具体的业务逻辑。
实现类接口(Implementor):定义了实现部分的接口,提供了具体的实现方法。
具体实现类(ConcreteImplementor):实现了实现部分的接口,提供具体的实现细节。
- img: https://bitouyun.com/images/design-pattern/bridge.png
link: https://bitouyun.com/images/design-pattern/bridge.png
name: 桥接模式
2
3
如何确定抽象类和实现类接口
确定抽象类和实现类接口需要考虑系统的设计目标、变化部分和需求,以及语言特性和设计的灵活性。关键是分离变化部分,并建立合适的抽象和实现关系,以实现系统的可扩展性和灵活性。
抽象类(Abstraction)代表高层逻辑,定义了抽象部分的接口和方法,其中包含一个对实现类接口的引用。抽象类可以是一个抽象类(abstract class)或者一个接口(interface),具体取决于编程语言的特性和设计的需要。
实现类接口(Implementor)代表实现部分的接口,定义了实现部分的具体方法。实现类接口可以是一个接口(interface)或者一个具体类(concrete class),也取决于编程语言的特性和设计的需要。
在确定抽象类和实现类接口时,需要考虑以下几点:
分离变化部分:抽象类和实现类接口的目的是将系统中的变化部分解耦,使它们可以独立变化。因此,需要确定哪些部分是变化的,哪些部分是稳定的。
定义抽象接口:根据变化部分的抽象程度,确定抽象类或接口的方法和接口。抽象接口应该能够满足系统需求,并提供足够的灵活性。
定义实现接口:根据抽象接口的需求,确定实现类接口的方法和接口。实现接口应该提供具体的实现逻辑,以满足抽象接口的要求。
建立关联关系:在抽象类中包含一个对实现类接口的引用,以便在抽象类中调用实现类接口的方法。这种关联关系可以通过构造函数、方法参数或者其他方式建立。
# 优点
分离抽象和实现:将抽象部分和实现部分分离,使它们可以独立变化。这样可以更灵活地扩展和修改系统的各个部分。
提高可扩展性:由于抽象部分和实现部分可以独立扩展,桥接模式使得系统更容易适应变化和扩展新的功能。
隐藏实现细节:通过将抽象部分和实现部分解耦,可以隐藏实现的细节,使得客户端只需要关注抽象接口,简化了客户端的使用。
支持运行时绑定:允许在运行时选择具体的实现部分,从而实现动态绑定,提供了更大的灵活性。
# 缺点
增加系统复杂性:引入桥接模式会增加额外的类和对象,增加了系统的复杂性,对于简单的系统可能会显得过于繁琐。
增加开发成本:设计和实现桥接模式需要额外的工作量,包括定义抽象部分和实现部分的接口,以及编写桥接类等。
# 应用场景
当希望抽象部分和实现部分可以独立变化,且需要动态绑定时,可以考虑使用桥接模式。
当一个类存在多个维度的变化,且每个维度都需要独立扩展时,可以使用桥接模式。
当希望在抽象部分和实现部分之间建立稳定的关联关系,但又不希望两者紧密耦合时,可以使用桥接模式。
当需要隐藏实现细节,使客户端只关注抽象接口时,可以考虑使用桥接模式。
# 示例代码1
场景1
实现一款支持多平台(Windows、Mac)、播放多种格式(mp3、wav)的音频播放器。
/**
* 音频播放器抽象类
*/
public abstract class AudioPlayer {
// 持有实现类的引用
protected Platform platform;
public AudioPlayer(Platform platform) {
this.platform = platform;
}
public abstract void play();
}
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Mp3播放器扩展抽象类
*/
public class Mp3Player extends AudioPlayer {
private String fileName;
public Mp3Player(Platform platform, String fileName) {
super(platform);
this.fileName = fileName;
}
@Override
public void play() {
platform.playMp3(fileName);
}
}
/**
* Wav播放器扩展抽象类
*/
public class WavPlayer extends AudioPlayer {
private String fileName;
public WavPlayer(Platform platform, String fileName) {
super(platform);
this.fileName = fileName;
}
@Override
public void play() {
platform.playWav(fileName);
}
}
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
/**
* 平台实现类接口
*/
public interface Platform {
void playMp3(String fileName);
void playWav(String fileName);
}
2
3
4
5
6
7
/**
* Windows平台具体实现类
*/
@Slf4j
public class WindowsPlatform implements Platform {
@Override
public void playMp3(String fileName) {
log.info("Windows平台播放mp3文件:{}", fileName);
}
@Override
public void playWav(String fileName) {
log.info("Windows平台播放wav文件:{}", fileName);
}
}
/**
* Mac平台具体实现类
*/
@Slf4j
public class MacPlatform implements Platform {
@Override
public void playMp3(String fileName) {
log.info("mac平台播放mp3文件:{}", fileName);
}
@Override
public void playWav(String fileName) {
log.info("mac平台播放wav文件:{}", fileName);
}
}
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
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
// 创建平台实现类
Platform windowsPlatform = new WindowsPlatform();
Platform macPlatform = new MacPlatform();
// 创建播放器抽象类
AudioPlayer mp3Player = new Mp3Player(windowsPlatform, "yesterday once more.mp3");
AudioPlayer wavPlayer = new WavPlayer(macPlatform, "trouble is a friend.wav");
// 播放音乐
mp3Player.play();
wavPlayer.play();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Make sure to add code blocks to your code group
# 示例代码2
场景2
向不同平台(安卓、IOS)推送消息,消息类型有通知消息、自定义消息、富文本消息和本地通知消息。
/**
* 消息抽象类
*/
public abstract class Message {
// 持有实现类接口引用
protected PushPlatform pushPlatform;
public Message(PushPlatform pushPlatform) {
this.pushPlatform = pushPlatform;
}
public abstract void send();
}
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 通知消息扩展抽象类
*/
public class NoticeMessage extends Message {
private String phoneNumber;
private String content;
public NoticeMessage(PushPlatform pushPlatform, String phoneNumber, String content) {
super(pushPlatform);
this.phoneNumber = phoneNumber;
this.content = content;
}
@Override
public void send() {
pushPlatform.sendSMS(phoneNumber, content);
}
}
/**
* 自定义消息扩展抽象类
*/
public class CustomMessage extends Message {
private String phoneNumber;
private String content;
public CustomMessage(PushPlatform pushPlatform, String phoneNumber, String content) {
super(pushPlatform);
this.phoneNumber = phoneNumber;
this.content = content;
}
@Override
public void send() {
pushPlatform.sendSMS(phoneNumber, content);
}
}
/**
* 富媒体消息扩展抽象类
*/
public class RichMediaMessage extends Message {
private String phoneNumber;
private String content;
public RichMediaMessage(PushPlatform pushPlatform, String phoneNumber, String content) {
super(pushPlatform);
this.phoneNumber = phoneNumber;
this.content = content;
}
@Override
public void send() {
pushPlatform.sendSMS(phoneNumber, content);
}
}
/**
* 本地通知消息扩展抽象类
*/
public class LocalMessage extends Message {
private String phoneNumber;
private String content;
public LocalMessage(PushPlatform pushPlatform, String phoneNumber, String content) {
super(pushPlatform);
this.phoneNumber = phoneNumber;
this.content = content;
}
@Override
public void send() {
pushPlatform.sendSMS(phoneNumber, content);
}
}
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
/**
* 推送平台实现类接口
*/
public interface PushPlatform {
void sendSMS(String phoneNumber, String content);
}
2
3
4
5
6
/**
* 安卓平台具体实现类
*/
@Slf4j
public class AndroidPlatform implements PushPlatform {
@Override
public void sendSMS(String phoneNumber, String content) {
log.info("安卓平台发送消息,手机号:{},内容:{}", phoneNumber, content);
}
}
/**
* IOS平台具体实现类
*/
@Slf4j
public class IosPlatform implements PushPlatform {
@Override
public void sendSMS(String phoneNumber, String content) {
log.info("IOS平台发送消息,手机号:{},内容:{}", phoneNumber, content);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
PushPlatform androidPlatform = new AndroidPlatform();
PushPlatform iosPlatform = new IosPlatform();
Message noticeMessage = new NoticeMessage(androidPlatform, "13100006789", "通知消息");
CustomMessage customMessage = new CustomMessage(iosPlatform, "13100006789", "自定义消息");
Message richMediaMessage = new RichMediaMessage(androidPlatform, "13100006789", "富文本消息");
Message localMessage = new LocalMessage(iosPlatform, "13100006789", "本地通知消息");
noticeMessage.send();
customMessage.send();
richMediaMessage.send();
localMessage.send();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Make sure to add code blocks to your code group