参考:https://blog.csdn.net/weixin_48052161/article/details/119188465?spm=1001.2014.3001.5501
桥接模式:
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。
生活案例:
在现实生活中,某些类具有两个或多个维度的变化,如图形既可按形状分,又可按颜色分。如何设计类似于 Photoshop 这样的软件,能画不同形状和不同颜色的图形呢?如果用继承方式,m 种形状和 n 种颜色的图形就有m×n种,不但对应的子类很多,而且扩展困难。
相机可以按,品牌(索尼,佳能等)和相机类型(单反,微单,卡片机等)两种维度去组合结果
抽象类在发展 实现类也在发展
需求:
一个哥哥要送妹妹礼物,但知道选什么样的礼物,产生烦恼
礼物可以抽象划分可以分为温柔的礼物和狂野的礼物 WarmGift ,WildGift
礼物按实际类别又可以分为书本和花朵Book,Flower
不同的分类,有不同的表达:按礼物的大的方向,可以对礼物类进行分类,而按照礼物具体的本身又有不同的分类:接口里面套接口
即:实际需求 可能Flower又可以分为WarmFlower ,WildFlower.
书本也可以分为WarmBook ,WildBook.
如果再有别的礼物,比如抽象类型:ToughGift ColdGift
或者具体的某种实现:Ring Car
抽象类在发展 实现类也在发展…
全都用继承的话就会产生类的爆炸 WarmCar ColdRing WildCar WildFlower …
使用桥接模式:
分离抽象与具体实现,让他们可以独自发展
用聚合 代替继承
代码阐述:
原理:礼物的抽象类里面聚合了礼物的实现接口,即
package com.example.dtest.design24.bridgeMode;
public abstract class Gift {
GiftImpl impl;
}
实现抽象分类的类:
package com.example.dtest.design24.bridgeMode;
public class WarmGift extends Gift {
public WarmGift(GiftImpl impl){
this.impl = impl;
}
public WarmGift(){
}
}
package com.example.dtest.design24.bridgeMode;
public class WildGift extends Gift {
public WildGift(GiftImpl impl){
this.impl = impl;
}
public WildGift(){
}
}
礼物的具体分类接口:
package com.example.dtest.design24.bridgeMode;
public interface GiftImpl {
}
实现具体分类的类:
package com.example.dtest.design24.bridgeMode;
public class Book implements GiftImpl{
}
package com.example.dtest.design24.bridgeMode;
public class Flower implements GiftImpl{
}
最后测试实现不同抽象分类实现不同的具体实体类:
package com.example.dtest.design24.bridgeMode;
public class BridgeModeTest {
public static void main(String[] args) {
//温柔的花 WarmFlower
Gift g = new WarmGift(new Flower());
//野性的书本 WildBook
Gift g1 = new WildGift(new Book());
}
}
总结:即把抽象分类的抽象类,和具体实现的接口以聚合方式连体(即实现类的接口以属性方式放在顶层抽象类的属性里面),最后构造器将具体的类放在实现抽象类的类里面。桥接:即桥梁的意思,则有一个类承担了输入和输出的不同性,即这个类输入的是该类的具体的实现,但输出的是抽象的大实现或者顶层抽象,又或者输出的是一致的某一个接口
扩展:JDBC中使用的桥接模式:
JDBC为所有的关系型数据库提供一个通用的界面。一个应用系统动态地选择一个合适的驱动器,然后通过驱动器向数据库引擎发出指令。
我们知道jdbc只提出了一系列接口规范,具体的实现由数据库提供者去实现。所以,当我们在连接mysql的时候,需要添加jdbc-mysql.jar,在连接oracel的时候,需要添加ojdbc.jar。然后去载入驱动,再进行连接.
代码:
package com.example.dtest.jdbc;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
@Component
public class JdbcConnection {
public static Connection getConn() {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://42.192.41.114:3306/dblogs";
String username = "root";
String password = "123456";
Connection conn = null;
try {
Class.forName(driver); //classLoader,加载对应驱动
conn = (Connection) DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
com.mysql.jdbc.Driver 源码:
import java.sql.DriverManager;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
Class.forName会把类加载进来,执行类的静态方法(类加载的初始化阶段)。我们看到mysql Driver的static块,调用了java.sql.DriverManager的registerDriver方法来注册驱动。
当驱动注册完成后,我们就会开始调用DriverManager中的getConnection方法获取数据库连接对象Connection
在Java中通过Connection提供给各个数据库一样的操作接口,这里的Connection可以看作抽象类
所以这里 Driver(数据库驱动接口)
和Connection(数据库连接接口)之间
是通过DriverManager类进行桥接的
总结:即把抽象分类的抽象类,和具体实现的接口以聚合方式连体(即实现类的接口以属性方式放在顶层抽象类的属性里面),最后构造器将具体的类放在实现抽象类的类里面。桥接:即桥梁的意思,则有一个类承担了输入和输出的不同性,即这个类输入的是该类的具体的实现,但输出的是抽象的大实现或者顶层抽象,又或者输出的是一致的某一个接口