桥接模式---Bridge
Posted 高高for 循环
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了桥接模式---Bridge相关的知识,希望对你有一定的参考价值。
桥接模式
定义:
GOF 在《设计模式》中给桥梁模式的定义为:将抽象部分与它的实现部分分离,使它 们都可以独立地变化
- 桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
- 这种模式涉及到一个作为桥接的接口,使得实体类的功能独立于接口实现类。这两种类型的类可被结构化改变而互不影响。
实质:
用聚合 代替继承
- 桥接模式的主要目的是通过组合的方式建立两个类之间的关系,而并不通过继承来实现,桥接模式的核心在于解耦抽象和实现。
生活案例:
- 在现实生活中,某些类具有两个或多个维度的变化,如图形既可按形状分,又可按颜色分。如何设计类似于 Photoshop 这样的软件,能画不同形状和不同颜色的图形呢?如果用继承方式,m 种形状和 n 种颜色的图形就有m×n种,不但对应的子类很多,而且扩展困难。
- 相机可以按,品牌(索尼,佳能等)和相机类型(单反,微单,卡片机等)两种维度去组合结果
抽象类在发展 实现类也在发展
组成:
案例 1
需求:
一个GG要送MM礼物,但知道选什么样的礼物,产生烦恼
- 礼物可以抽象划分可以分为温柔的礼物和狂野的礼物 WarmGift ,WildGift
- 礼物按实际类别又可以分为书本和花朵Book,Flower
抽象角色 礼物 Gift:
public interface Gift {
}
抽象划分:
//温柔的礼物
public class WarmGift implements Gift{
}
//狂野的礼物
class WildGift implements Gift {
}
实际类别划分:
//书本
public class Book implements Gift {
}
//花朵
class Flower implements Gift {
}
分析:
- 但实际需求 可能Flower又可以分为WarmFlower ,WildFlower.
书本也可以分为WarmBook ,WildBook. - 如果再有别的礼物,比如抽象类型:ToughGift ColdGift
或者具体的某种实现:Ring Car
抽象类在发展 实现类也在发展…
全都用继承的话就会产生类的爆炸 WarmCar ColdRing WildCar WildFlower …
使用桥接模式:
分离抽象与具体实现,让他们可以独自发展
用聚合 代替继承
- Gift -> WarmGift ColdGift WildGift
- GiftImpl -> Flower Ring Car
抽象角色 礼物 Gift01:
- 聚合一个精确抽象角色
public abstract class Gift01 {
GiftImpl impl;
}
精确抽象角色 GiftImpl
public interface GiftImpl {
}
实现角色:
//书本
public class Book implements GiftImpl {
}
//花朵
class Flower implements GiftImpl {
}
具体实现角色
//温柔的礼物
public class WarmGift extends Gift01{
public WarmGift(GiftImpl impl) {
this.impl = impl;
}
public WarmGift() {
}
}
//狂野的礼物
class WildGift extends Gift01 {
public WildGift(GiftImpl impl) {
this.impl = impl;
}
public WildGift() {
}
}
测试调用 Main
public class Main {
public static void main(String[] args) {
//温柔的花 WarmFlower
Gift01 g = new WarmGift(new Flower());
//野性的书本 WildBook
Gift01 g1 = new WildGift(new Book());
}
}
- 分离了抽象部分及其实现部分两个维度,实现了代码的解耦,提高了系统的扩展性。
- 并减少了子类数。
JDBC中的桥接模式
JDBC概念:
- JDBC为所有的关系型数据库提供一个通用的界面。一个应用系统动态地选择一个合适的驱动器,然后通过驱动器向数据库引擎发出指令。
- 我们知道jdbc只提出了一系列接口规范,具体的实现由数据库提供者去实现。所以,当我们在连接mysql的时候,需要添加jdbc-mysql.jar,在连接oracel的时候,需要添加ojdbc.jar。然后去载入驱动,再进行连接.
public class Test01 {
public static void main(String[] args) throws Exception {
//1.注册数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//2.获取数据库连接
Connection conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/jt_db?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8",
"root", "root");
//3.获取传输器
Statement stat = conn.createStatement();
//4.发送SQL到服务器执行并返回执行结果
String sql = "select * from account";
ResultSet rs = stat.executeQuery( sql );
//5.处理结果
while( rs.next() ) {
int id = rs.getInt("id");
String name = rs.getString("name");
double money = rs.getDouble("money");
System.out.println(id+" : "+name+" : "+money);
}
//6.释放资源
rs.close();
stat.close();
conn.close();
System.out.println("TestJdbc.main()....");
}
}
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类进行桥接的
总结:
使用场景:
当一个类内部具有两种及以上维度变化时,使用桥接模式可以解耦这些维度,使得高层代码结构稳定
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。可以考虑桥接模式
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用
- 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
优点:
- 分离了抽象部分及其实现部分两个维度,实现了代码的解耦,提高了系统的扩展性。
- 扩展功能时只需要新增类,无需修改源代码,符合开闭原则。
- 通过组合而不是继承来实现耦合,符合合成复用原则。
缺点:
- 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
实质:
分离抽象与具体实现,让他们可以独自发展
用聚合 代替继承
以上是关于桥接模式---Bridge的主要内容,如果未能解决你的问题,请参考以下文章