桥接模式
2021-04-14 本文已影响0人
lj72808up
桥接模式
-
思想: 组合优于继承
-
桥接模式有2种理解角度
- 将业务的抽象和业务的具体实现分开
- 当一个类存在2个以上的变化维度时, 通过组合, 让两个维度可以独立进行扩展
-
jdbc 就是使用桥接模式实现不同数据库的操作的
- 如下代码, 是 jdbc 的标准使用代码
Class.forName("com.mysql.jdbc.Driver");//加载及注册JDBC驱动程序 String url = "jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password"; Connection con = DriverManager.getConnection(url); Statement stmt = con.createStatement(); String query = "select * from test"; ResultSet rs=stmt.executeQuery(query); while(rs.next()) { rs.getString(1); rs.getInt(2); }
- 如果我们想要把 MySQL 数据库换成 Oracle 数据库,只需要把第一行代码中的
com.mysql.jdbc.Driver
换成oracle.jdbc.driver.OracleDriver
就可以了. 为什么可以这样呢? 原因在com.mysql.jdbc.Driver
这个类
package com.mysql.jdbc; public class Driver extends NonRegisteringDriver implements java.sql.Driver { static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } /** * Construct a new driver and register it with DriverManager * @throws SQLException if a database error occurs. */ public Driver() throws SQLException { // Required for Class.forName().newInstance() } }
我们可以发现,当执行 Class.forName(“com.mysql.jdbc.Driver”) 这条语句的时候,实际上是做了两件事情。
* 第一件事情是要求 JVM 查找并加载指定的 Driver 类
* 第二件事情是执行该类的静态代码块,也就是将自己mysql.Driver
注册到 DriverManager 类中。经过以上分析返现, 各数据库自己的驱动注册到 DriverManager 后, 就能实现不同数据库自己的操作.
DriverManager
就是业务的抽象,mysql.Driver
就是业务的实现. 可以看到,DriverManager.getConnection
组合了Driver.connect()
方法public class DriverManager { private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>(); //... static { loadInitialDrivers(); println("JDBC DriverManager initialized"); } //... public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException { if (driver != null) { registeredDrivers.addIfAbsent(new DriverInfo(driver)); } else { throw new NullPointerException(); } } public static Connection getConnection(String url, String user, String password) throws SQLException { java.util.Properties info = new java.util.Properties(); if (user != null) { info.put("user", user); } if (password != null) { info.put("password", password); } return (getConnection(url, info, Reflection.getCallerClass())); } //... }
- 假设要实现一个 API 接口监控告警的例子:根据不同的告警规则,触发不同类型的告警。
- 告警渠道有多个, 包括:邮件、短信、微信、自动语音电话。
- 告警的紧急程度有个,包括:SEVERE(严重)、URGENCY(紧急)、NORMAL(普通)、TRIVIAL(无关紧要)。
因为告警这个动作有2个变化维度: 渠道和严重程度. 因此可以把2个维度的协作方式作为业务的抽象, 2个维度各自的执行作为业务的具体实现
// 业务的具体实现
interface MsgSender {
void send(String message);
}
class TelephoneMsgSender implements MsgSender {
private List<String> telephones;
public TelephoneMsgSender(List<String> telephones) {
this.telephones = telephones;
}
@Override
public void send(String message) {
//...
}
}
class EmailMsgSender implements MsgSender {
// 与TelephoneMsgSender代码结构类似,所以省略...
}
class WechatMsgSender implements MsgSender {
// 与TelephoneMsgSender代码结构类似,所以省略...
}
// 业务的抽象
abstract class Notification {
protected MsgSender msgSender;
public Notification(MsgSender msgSender) {
this.msgSender = msgSender;
}
public abstract void notify(String message);
}
class SevereNotification extends Notification {
public SevereNotification(MsgSender msgSender) {
super(msgSender);
}
@Override
public void notify(String message) {
msgSender.send(message);
}
}
class UrgencyNotification extends Notification {
// 与SevereNotification代码结构类似,所以省略...
}
class NormalNotification extends Notification {
// 与SevereNotification代码结构类似,所以省略...
}
class TrivialNotification extends Notification {
// 与SevereNotification代码结构类似,所以省略...
}