桥接模式
将抽象和实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合。
⭐什么时候用桥接模式
假设现在我们有一个需求,要创建不同的图形,每个图形都可能会有不同的颜色,最简单的情况:我们用继承的方式来设计
现在我们就得到了很多类,如果我们还需要再加一个形状或再添加一种颜色,就需要创建更多的类。
这时我们为了避免类爆炸的情况,就可以使用桥接模式!
⭐结构
- 抽象化角色——定义抽象类,并包含一个对实现化对象的引用
- 扩展抽象化角色——是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法
- 实现化角色——定义实现化角色的接口,供扩展抽象化角色调用
- 具体实现化角色——给出实现化角色接口的具体实现
🌰举个例子
我们现在需要开发一个跨平台视频播放器,可以在不同操作系统平台上播放多种格式的视频文件,常见的视频格式包括RMVB、AVI、WMV等等。该播放器包含了两个维度,适合使用桥接模式。
设计类图如下:
这里将音频文件都定义成VideoFile接口或抽象类供各种视频文件的具体类实现或继承,再将其聚合进操作系统类中,这里的VideoFile就是实现化角色,继承或实现它的类,例如AVIFile、RMVBFile就是具体实现化角色
而这里的OperatingSystem就是抽象化角色,其中引用实现化对象
Windows和Mac就是扩展抽象化角色
我们来具体实现:
public interface VideoFile {
void decode(String fileName)
}
public class AviFile implements VideoFile {
public void decode(String fileName) {
System.out.println("avi视频文件");
}
}
//RmvbFile.class与之类似,不再赘述
public abstract class OperatingSystem {
protected VideoFile videoFile;
public OperatingSystem(VideoFile videoFile) {
this.videoFile = videoFile;
}
public abstract void play(String fileName);
}
public class Windows extends OperatingSystem {
public Windows(VideoFile videoFile) {
super(videoFile);
}
public void play(String fileName) {
videoFile.decode(fileName);
}
}
//Mac.class同理,这里也不再赘述
现在我们去测试类中就可以很简单的使用不同的操作系统播放不同的视频文件啦:
//client
//先创建具体的操作系统对象
OperatingSystem system = new Mac(new AviFile());
//使用操作系统播放视频文件
system.play("big fish");
⭐使用桥接模式的优势
- 提高了系统的可扩展性,在两个维度中任意扩展一个维度,都不需要再修改原有系统
- 实现细节对客户透明