鸣谢:《大话设计模式》
简介
结构型设计模式,它将一个对象的抽象部分与它的实现部分分离开来,以便它们可以独立地变化。桥接模式的核心思想是将抽象和实现解耦,从而使它们可以独立地进行扩展和修改。
按我的理解,桥接模式就是多个类的抽象组合了一个接口或者抽象类,不依赖于具体而是全部依赖于抽象。 没使用继承,使得耦合性降低
(抽象和实现分离,通过组合将他们连接起来)
桥接模式在一定程度上可以避免子类过多,子类剧增,子类爆炸的情况,抽象和实现可以独立发展,在这个模式中组合优于继承
主要组成部分:
- 抽象(Abstraction):抽象是一个抽象类或接口,它定义了对客户端可见的高级操作和行为,通常包含对实现的引用。抽象类的子类可以提供不同的具体实现。
-
扩展抽象(Refined Abstraction):扩展抽象是抽象的子类,它扩展了抽象类的行为,通常与特定实现相关。它通过组合抽象和实现的方式来实现高级操作。
-
实现(Implementor):实现是一个接口,它定义了具体实现部分的方法,通常包含了一些基本操作。多个实现类可以提供不同的实现。
-
具体实现(Concrete Implementor):具体实现是实现接口的具体类,它实现了实现部分的具体方法。
工作流程
-
抽象类引用实现接口,并定义高级操作。这确保了抽象和实现的关联,但允许它们独立变化。
-
扩展抽象类继承自抽象类,并可以进一步定义和扩展高级操作。
-
实现类实现实现接口,提供具体的实现。
-
客户端使用抽象类和具体实现类进行组合,以实现所需的功能。
例子
结构
这里例子的背景是很久以前没有应用商店,每个app都是和手机绑定的,传统按键机的时代
代码
抽象(Abstraction)
public abstract class PhoneBrand {
protected ApkSoftware software;
public void setApk(ApkSoftware software){
this.software = software;
}
public ApkSoftware getSoftware(){
return software;
}
public abstract void run();
}
扩展抽象(Refined Abstraction)
/**
* @author: lpy
* @Date: 2023/11/01
*/
public class IQOO extends PhoneBrand{
@Override
public void run() {
System.out.println("运行:");
softwate.run();
}
}
/**
* @author: lpy
* @Date: 2023/11/01
*/
public class Apple extends PhoneBrand{
@Override
public void run() {
System.out.println("运行:");
softwate.run();
}
}
实现(Implementor)
不要学的太死,这里也可以是接口啊
/**
* @author: lpy
* @Date: 2023/11/01
*/
public abstract class ApkSoftware {
protected String name;
public ApkSoftware(String name){
this.name = name;
}
public String getName() {
return name;
}
abstract void run();
}
具体实现(Concrete Implementor)
/**
* @author: lpy
* @Date: 2023/11/01
*/
public class KugouMusic extends ApkSoftware{
public KugouMusic(String name) {
super(name);
}
@Override
void run() {
System.out.println(name+"运行了");
}
}
/**
* @author: lpy
* @Date: 2023/11/01
*/
public class Wechat extends ApkSoftware{
public Wechat(String name) {
super(name);
}
@Override
void run() {
System.out.println(name+"运行了");
}
}
测试类
/**
* @author: lpy
* @Date: 2023/11/01
*/
public class TestBridgeMode {
public static void main(String[] args) {
Apple ap = new Apple();
ap.setApk(new KugouMusic("酷狗"));
ap.run();
ap.setApk(new Wechat("wechat"));
ap.run();
IQOO iqoo = new IQOO();
iqoo.setApk(new KugouMusic("kg"));
iqoo.run();
iqoo.setApk(new Wechat("xw"));
iqoo.run();
}
}
应用
- 操作系统驱动程序:操作系统驱动程序通常需要适配多种硬件设备,桥接模式可用于将抽象操作系统接口与不同硬件设备的具体实现分离开来。这允许在不修改操作系统代码的情况下添加新的硬件设备支持。
-
图形用户界面工具包:图形用户界面(GUI)工具包需要适应不同的操作系统和窗口系统。桥接模式可用于将抽象 GUI 元素(按钮、文本框等)与不同操作系统的具体实现分离开来,以确保跨平台兼容性。
-
数据库连接库:数据库连接库需要支持多种数据库管理系统(如MySQL、Oracle、SQL Server等)。桥接模式可用于将抽象数据库连接接口与不同数据库的具体实现分离,以实现跨数据库的数据访问。
-
音频和视频播放器:多媒体播放器需要适配不同的音频和视频编解码器。桥接模式可用于将抽象媒体播放接口与不同编解码器的具体实现分离,以支持多种媒体格式。
-
电子设备遥控器:电子设备遥控器需要适配不同品牌和类型的电子设备,如电视、音响等。桥接模式可用于将抽象遥控器接口与不同设备的具体实现分离,以实现通用的遥控器。
-
游戏引擎:游戏引擎需要适应不同平台和图形 API。桥接模式可用于将抽象图形引擎接口与不同平台和图形 API 的具体实现分离,以实现跨平台游戏开发。
源码中的影子
java.sql包下的Driver接口就是桥接模式中的实现部分,MysqlDriver,OricleDriver都实现这个接口,DriverManager里面有一个属性DriverInfo,而DriverInfo又是对Driver的封装,DriverManager
对外提供了操作数据库的统一接口getConnection(),获取不同的数据库连接,返回值Connection接口 有各种操作数据库的接口
public class DriverManager {
// List of registered JDBC drivers
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
public static synchronized void registerDriver(java.sql.Driver driver,
DriverAction da)
throws SQLException {
/* Register the driver if it has not already been added to our list */
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
}
class DriverInfo {
final Driver driver;
DriverAction da;
DriverInfo(Driver driver, DriverAction action) {
this.driver = driver;
da = action;
}
@Override
public boolean equals(Object other) {
return (other instanceof DriverInfo)
&& this.driver == ((DriverInfo) other).driver;
}
@Override
public int hashCode() {
return driver.hashCode();
}
@Override
public String toString() {
return ("driver[className=" + driver + "]");
}
DriverAction action() {
return da;
}
}
桥接模式优缺点
- 优点:
- 解耦合:桥接模式将抽象和实现解耦,使它们可以独立变化。这提高了系统的灵活性,使扩展和修改更容易。
-
高内聚:桥接模式鼓励高内聚,因为它强调将相关的抽象和实现组合在一起,从而提高了代码的可读性和维护性。
-
支持多维度变化:通过抽象和实现的组合,可以支持多维度的变化,例如在不同抽象和不同实现之间进行组合。
-
遵循开闭原则:桥接模式遵循开闭原则,允许在不修改现有代码的情况下引入新的抽象或实现。
-
简化继承:相对于使用多层继承来处理不同变化维度,桥接模式提供了更简洁的方式。
-
缺点:
- 复杂性增加:引入桥接模式会增加类的数量和层次结构,从而增加代码的复杂性。这可能会使代码更难理解,尤其是在处理较为简单的情况时可能会显得过于繁琐。
-
维护成本:管理抽象和实现之间的关系需要额外的工作,尤其是在系统中有多个实现和多个扩展抽象时。这可能会增加维护成本。
-
适用性限制:桥接模式并不是适用于所有情况。对于一些简单的情况,它可能显得过于复杂,不值得引入。
-
抽象和实现的耦合:虽然桥接模式鼓励解耦,但仍然需要在抽象和实现之间建立某种关系,这可能会导致某种程度的耦合。在一些情况下,这种耦合可能难以避免。
-
理解成本:开发人员需要理解桥接模式的工作原理和规范,这可能需要一些额外的学习和培训成本。
7 大设计原则
不能全部遵守 , 也不能不遵守 , 注意平衡 功能 和 系统复杂度 , 找到最合适的一个点 ;
- 单一职责原则(Single Responsibility Principle - SRP):
这个原则规定一个类应该只有一个改变的理由,也就是说,一个类应该只有一个单一的职责。这有助于保持类的简单性和可维护性,因为每个类只需关注一个特定的功能。
- 开放-封闭原则(Open-Closed Principle - OCP):
开放-封闭原则要求系统中的软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。这意味着当需要添加新功能时,应该通过扩展现有代码来实现,而不是修改原有代码。
- 里氏替换原则(Liskov Substitution Principle - LSP):
里氏替换原则规定,子类应该能够替换其父类,而不会影响程序的正确性。也就是说,子类应该继承父类的行为,但可以扩展或修改该行为,但不应该改变父类的行为。
- 接口隔离原则(Interface Segregation Principle - ISP):
接口隔离原则要求一个类不应该强迫其客户端依赖于它们不需要的接口。应该根据客户端的需求定义小而精确的接口,而不是大而笨重的接口。
- 依赖倒置原则(Dependency Inversion Principle - DIP):
依赖倒置原则要求高级模块不应该依赖于低级模块,它们都应该依赖于抽象。具体来说,这意味着应该通过抽象接口或抽象类来定义模块之间的依赖关系,而不是直接依赖于具体实现。
- 迪米特法则(Law of Demeter - LoD):
如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
- 合成复用原则(Composite Reuse Principle - CRP):
合成复用原则鼓励通过组合(合成)已有的类来实现新功能,而不是通过继承现有的类。这样可以降低系统的耦合度,并且更加灵活。
源码位置
全部源码github.com/xs-alpha/designPattern
参考文献
- 《大话设计模式》
-
慕课视频《Java设计模式精讲 Debug方式+内存分析》
如有内容侵权,麻烦联系博主删除