当一件事情有多个维度的变化的可能性时,桥接模式就派上用场了。如下图,一个消息系统中,发送消息的方式 和消息的类型都是可以独立变化的,两个维度的变化互不影响,比如消息可以通过邮件发送,而消息类型可以使普通消息,加急消息, 还可以通过短信来发送普通消息或者加急消息,这样的系统就很适合桥接模式来实现。 每个独立变化的维度分别抽象出一个独立的接口,然后通过一个“桥”来持有这两个维度的顶层接口,来实现自己的业务逻辑:
消息发送接口:
package com.lchtest.pattern.birdge.message;
public interface IMessage {
void send(String msg, String reciever);
}
消息发送方式:
package com.lchtest.pattern.birdge.message;
public class EmailMessage implements IMessage {
@Override
public void send(String msg, String reciever) {
System.out.println(String.format("使用邮件发送消息 %s 给 %s ", msg, reciever));
}
}
package com.lchtest.pattern.birdge.message;
public class SystemMessage implements IMessage {
@Override
public void send(String msg, String reciever) {
System.out.println(String.format("使用内部消息系统发送消息 %s 给 %s ", msg, reciever));
}
}
建立桥接:
package com.lchtest.pattern.birdge.message;
public abstract class AbstractMessage {
private IMessage message;
public AbstractMessage(IMessage message) {
this.message = message;
}
void send(String msg, String reciever){
this.message.send(msg, reciever);
}
}
消息级别:
package com.lchtest.pattern.birdge.message;
public class NormalMessage extends AbstractMessage {
public NormalMessage(IMessage message) {
super(message);
}
@Override
void send(String msg, String reciever) {
super.send(msg, reciever);
}
}
package com.lchtest.pattern.birdge.message;
public class UrgencyMessage extends AbstractMessage {
public UrgencyMessage(IMessage message) {
super(message);
}
@Override
void send(String msg, String reciever) {
String urgencyMessage = "【加急】" + msg;
super.send(urgencyMessage, reciever);
}
}
测试类:
package com.lchtest.pattern.birdge.message;
public class Test {
public static void main(String[] args) {
IMessage message = new EmailMessage();
AbstractMessage abstractMessage = new NormalMessage(message);
AbstractMessage urgencyMessage = new UrgencyMessage(message);
abstractMessage.send("便携式测温仪采购申请","采购经理");
urgencyMessage.send("紧急事务处理款项申请","老板");
message = new SystemMessage();
abstractMessage = new UrgencyMessage(message);
abstractMessage.send("便携式测温仪采购申请","公司老板");
}
}
以JDBC API的抽象维度和实现维度 为例,来说明源码中的桥接是怎么使用的
package com.lchtest.pattern.birdge;
import lombok.Data;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class JDBCBridge {
public static void main(String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "lchadmin");
String sql = "select * from user where id= ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setInt(1, 1);
pstmt.execute();
ResultSet rs = pstmt.getResultSet();
while (rs.next()){
User user = new User();
user.setId(rs.getInt("id"));
user.setAge(rs.getInt("age"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
System.out.println(user.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Data
class User {
private int id;
private String username;
private String password;
private int age;
}
Class.forName代码的作用
Class.forName(“com.mysql.jdbc.Driver”) 加载Driver类的时候就会执行如下的静态代码块 最终调用了下面的方法:
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
代码的核心就是把Driver的实例放到了registeredDrivers 这个list里面去了,而不管是哪种数据库的Driver实例,都给封装成了DriverInfo对象,
DriverManager.getConnection的底层逻辑
getConnection核心逻辑如下,遍历那个registeredDrivers ,调用driver自己的connect方法,而这个driver就是之前的com.mysql.jdbc.Driver 的实例, 调用的connect是 driver的父类NonRegisteringDriver中的connect方法,返回的Connection对象也是实现了java.sql.Connection接口的实例。
|