适配器设计模式实战2
一.目的
结合源码来深入理解适配器模式,本文通过java.sql的源码来讲解适配器模式的思想
适配器模式介绍可参考 适配器模式实战1
二.业务场景介绍
在编写服务端代码时,我们需要使用数据库,而数据库种类繁多,最常用的关系型数据库mysql,oracle等,不同的数据库由不同的组织和公司开发,所以api不可能完全做的一样,而jdk为了适配不同类型的数据库,提供了Driver接口和DriverManager类,为我们执行数据库业务提供了同一的接口.
三.角色划分
四.具体代码
java.sql.Driver代码
public interface Driver { Connection connect(String url, java.util.Properties info) throws SQLException; boolean acceptsURL(String url) throws SQLException; DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info) throws SQLException; int getMajorVersion(); int getMinorVersion(); boolean jdbcCompliant(); public Logger getParentLogger() throws SQLFeatureNotSupportedException; }
com.mysql.jdbc.NonRegisteringDriver 代码
public class NonRegisteringDriver implements Driver{ //... public Connection connect(String url, Properties info) throws SQLException { if (url != null) { if (StringUtils.startsWithIgnoreCase(url, "jdbc:mysql:loadbalance://")) { return this.connectLoadBalanced(url, info); } if (StringUtils.startsWithIgnoreCase(url, "jdbc:mysql:replication://")) { return this.connectReplicationConnection(url, info); } } Properties props = null; if ((props = this.parseURL(url, info)) == null) { return null; } else if (!"1".equals(props.getProperty("NUM_HOSTS"))) { return this.connectFailover(url, info); } else { try { com.mysql.jdbc.Connection newConn = ConnectionImpl.getInstance(this.host(props), this.port(props), props, this.database(props), url); return newConn; } catch (SQLException var6) { throw var6; } catch (Exception var7) { SQLException sqlEx = SQLError.createSQLException(Messages.getString("NonRegisteringDriver.17") + var7.toString() + Messages.getString("NonRegisteringDriver.18"), "08001", (ExceptionInterceptor)null); sqlEx.initCause(var7); throw sqlEx; } } } //... }
com.mysql.jdbc.Driver
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("com.mysql.jdbc.Driver") 时,该驱动会被注册到DriverManager里
OracleDriver
public class OracleDriver implements Driver{ //... public Connection connect(String var1, Properties var2) throws SQLException{ //... } //... }
public interface Connection extends Wrapper, AutoCloseable{ Statement createStatement() throws SQLException; PreparedStatement prepareStatement(String sql) throws SQLException; CallableStatement prepareCall(String sql) throws SQLException; String nativeSQL(String sql) throws SQLException; void setAutoCommit(boolean autoCommit) throws SQLException; boolean getAutoCommit() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; boolean isClosed() throws SQLException; //..... }
com.mysql.jdbc.Connection
public interface Connection extends java.sql.Connection, ConnectionProperties{ //.... }
oracle.jdbc.OracleConnection
public interface OracleConnection extends Connection{ //... }
oracle.jdbc.OracleConnectionWrapper
public class OracleConnectionWrapper implements OracleConnection{ //... }
五.具体调用
//首先建立驱动 oracle Class.forName("oracle.jdbc.driver.OracleDriver"); //mysql Class.forName("com.mysql.jdbc.driver");
//数据库不同,接口都通用一个 //驱动成功后进行连接 conn=DriverManager.getConnection(url, user, password); //准备SQL语句 PreparedStatement pStatement = connection.prepareStatement(query); //执行SQL语句 ResultSet resultSet = pStatement.executeQuery();
六.总结
由此可见,jdbc采用了接口适配的思想,为我们调用数据库提供了同一接口,而不用管具体不同类型数据库的内部实现,既方便了调用,也方便了用配置文档类配置数据库相关信息