Java设计模式——桥接模式(Bridge)
2015-03-16 18:33
337 查看
桥接模式的意图是将抽象和抽象方法的实现相互分离来实现解耦,以便二者相互独立的变化。
若要通过共同的接口控制多种机器,可以使用适配器模式,为每个控制器创建一个适配器类,每个适配器类都可以讲标准的接口调用转换为对现有控制器的调用。
常规抽象:桥接模式的一种方法
数据库驱动
如果用Jdbc连接,只需要用不同的Class.forName参数即可,剩下的都一样。是用oracle还是mysql,只是一个参与的不同而已,然后下面都是一样的。
Class.forName(xxx.xx.xx)返回的是一个类
Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段(静态代码块在jar包)
new 和Class.forName()有什么区别?
它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。首先,newInstance( )是一个方法,而new是一个关键字。
其次,Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数,而使用 new关键字生成对象没有这个限制。
简言之:
newInstance(): 弱类型,低效率,只能调用无参构造。
new: 强类型,相对高效,能调用任何public构造。
Class.forName(“”)返回的是类。
Class.forName(“”).newInstance()返回的是object 。
原来Class.forName只是相当于在动态加载类。
通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为了动态加载类。
通常编码过程中,在加载完成后,一般还要调用Class下的newInstance( )静态方法来实例化对象以便操作。因此,单单使用Class.forName( )是动态加载类是没有用的,其最终目的是为了实例化对象。
为什么在加载数据库驱动包的时候有用的是Class.forName( ),却没有调用newInstance( )?
Class.forName(“”);的作用是要求JVM查找并加载指定的类,首先要明白,java里面任何class都要装载在虚拟机上才能运行,而静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了,而且以后不会再走这段静态代码了。
而我们前面也说了,Class.forName(xxx.xx.xx)的作用就是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码段。
而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的 Driver类的代码都必须类似如下:
既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。即使写上.newInstance()效果也是一样的。
当Class.forName(“com.mysql.jdbc.Driver”);用的时候,就相当于调用了Driver类中的java.sql.DriverManager.registerDriver(new Driver());,实例化一个Driver,然后再java.sql.DriverManager中进行注册。
我猜在Oracle的驱动ojdbc6类oracle.jdbc.driver.OracleDriver中也有一段java.sql.DriverManager.registerDriver(new Driver());,把自己注册给DriverManager。
通过上图可以看出,基于JDBC的应用程序,使用JDBC的API,相当于是对数据库操作的抽象的扩展,算作桥接模式的抽象部分;而具体的接口实现是由驱动来完成的,驱动这边自然就相当于桥接模式的实现部分了。而桥接的方式,不再是让抽象部分持有实现部分,而是采用了类似于工厂的做法,通过DriverManager来把抽象部分和实现部分对接起来,从而实现抽象部分和实现部分解耦。
JDBC的这种架构,把抽象和具体分离开来,从而使得抽象和具体部分都可以独立扩展。对于应用程序而言,只要选用不同的驱动,就可以让程序操作不同的数据库,而无需更改应用程序,从而实现在不同的数据库上移植;对于驱动程序而言,为数据库实现不同的驱动程序,并不会影响应用程序。而且,JDBC的这种架构,还合理的划分了应用程序开发人员和驱动程序开发人员的边界。
在源代码中:Connection con = aDriver.driver.connect(url, info); 这句话是重点,告诉我们 Connection是怎么来的。aDriver是从registeredDrivers来的,而Class.forName(“com.mysql.jdbc.Driver”);时,New了一个Driver注册给registeredDrivers的,此时再用driver.connect返回一个Connection的实例,这是一个回调!
Class.forName是用Mysql还是Oracle,这个Driver一定会实现接口java.sql.Driver,然后通过DriverManager.registerDriver(new Driver());使DriverManager类持有一个Driver,是否可以把DriverManager当成桥,当成桥连接中的抽象类?然后持有一个接口Driver,至于是Mysql还是Oracle,不关心,坐等传参。因为DriverManager持有的是一个Driver接口,你传过来什么,我就得到什么的实例化,然后我再通过getConnection用你的实例,去调用你自己的方法connect,去获得Connection的一个实例。
下面贴一下代码,再顺一下流程:
既然是com.mysql.jdbc.Driver实现,为什么没有实现 Driver的connect方法呢?原因是NonRegisteringDriver,它实现了java.sql.Driver接口,所以Driver就不用实现它了,Driver的目的只是为了注册,而去创建一个Connection则是由NonRegisteringDriver去完成的。最后贴一部分NonRegisteringDriver代码:
java.sql.DriverManager类
若要通过共同的接口控制多种机器,可以使用适配器模式,为每个控制器创建一个适配器类,每个适配器类都可以讲标准的接口调用转换为对现有控制器的调用。
常规抽象:桥接模式的一种方法
数据库驱动
如果用Jdbc连接,只需要用不同的Class.forName参数即可,剩下的都一样。是用oracle还是mysql,只是一个参与的不同而已,然后下面都是一样的。
Class.forName(xxx.xx.xx)返回的是一个类
Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段(静态代码块在jar包)
new 和Class.forName()有什么区别?
它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。首先,newInstance( )是一个方法,而new是一个关键字。
其次,Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数,而使用 new关键字生成对象没有这个限制。
简言之:
newInstance(): 弱类型,低效率,只能调用无参构造。
new: 强类型,相对高效,能调用任何public构造。
Class.forName(“”)返回的是类。
Class.forName(“”).newInstance()返回的是object 。
原来Class.forName只是相当于在动态加载类。
通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为了动态加载类。
通常编码过程中,在加载完成后,一般还要调用Class下的newInstance( )静态方法来实例化对象以便操作。因此,单单使用Class.forName( )是动态加载类是没有用的,其最终目的是为了实例化对象。
为什么在加载数据库驱动包的时候有用的是Class.forName( ),却没有调用newInstance( )?
Class.forName(“”);的作用是要求JVM查找并加载指定的类,首先要明白,java里面任何class都要装载在虚拟机上才能运行,而静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了,而且以后不会再走这段静态代码了。
而我们前面也说了,Class.forName(xxx.xx.xx)的作用就是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码段。
而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的 Driver类的代码都必须类似如下:
public class MyJDBCDriver implements Driver { static { DriverManager.registerDriver(new MyJDBCDriver()); } }
既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。即使写上.newInstance()效果也是一样的。
当Class.forName(“com.mysql.jdbc.Driver”);用的时候,就相当于调用了Driver类中的java.sql.DriverManager.registerDriver(new Driver());,实例化一个Driver,然后再java.sql.DriverManager中进行注册。
我猜在Oracle的驱动ojdbc6类oracle.jdbc.driver.OracleDriver中也有一段java.sql.DriverManager.registerDriver(new Driver());,把自己注册给DriverManager。
通过上图可以看出,基于JDBC的应用程序,使用JDBC的API,相当于是对数据库操作的抽象的扩展,算作桥接模式的抽象部分;而具体的接口实现是由驱动来完成的,驱动这边自然就相当于桥接模式的实现部分了。而桥接的方式,不再是让抽象部分持有实现部分,而是采用了类似于工厂的做法,通过DriverManager来把抽象部分和实现部分对接起来,从而实现抽象部分和实现部分解耦。
JDBC的这种架构,把抽象和具体分离开来,从而使得抽象和具体部分都可以独立扩展。对于应用程序而言,只要选用不同的驱动,就可以让程序操作不同的数据库,而无需更改应用程序,从而实现在不同的数据库上移植;对于驱动程序而言,为数据库实现不同的驱动程序,并不会影响应用程序。而且,JDBC的这种架构,还合理的划分了应用程序开发人员和驱动程序开发人员的边界。
在源代码中:Connection con = aDriver.driver.connect(url, info); 这句话是重点,告诉我们 Connection是怎么来的。aDriver是从registeredDrivers来的,而Class.forName(“com.mysql.jdbc.Driver”);时,New了一个Driver注册给registeredDrivers的,此时再用driver.connect返回一个Connection的实例,这是一个回调!
Class.forName是用Mysql还是Oracle,这个Driver一定会实现接口java.sql.Driver,然后通过DriverManager.registerDriver(new Driver());使DriverManager类持有一个Driver,是否可以把DriverManager当成桥,当成桥连接中的抽象类?然后持有一个接口Driver,至于是Mysql还是Oracle,不关心,坐等传参。因为DriverManager持有的是一个Driver接口,你传过来什么,我就得到什么的实例化,然后我再通过getConnection用你的实例,去调用你自己的方法connect,去获得Connection的一个实例。
下面贴一下代码,再顺一下流程:
package java.sql; import java.util.logging.Logger; 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; }</span> com.mysql.Driver类 import java.sql.SQLException; 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!"); } } public Driver() throws SQLException { // Required for Class.forName().newInstance() } }
既然是com.mysql.jdbc.Driver实现,为什么没有实现 Driver的connect方法呢?原因是NonRegisteringDriver,它实现了java.sql.Driver接口,所以Driver就不用实现它了,Driver的目的只是为了注册,而去创建一个Connection则是由NonRegisteringDriver去完成的。最后贴一部分NonRegisteringDriver代码:
public class NonRegisteringDriver implements java.sql.Driver { public java.sql.Connection connect(String url, Properties info) throws SQLException { ...... try { Connection newConn = com.mysql.jdbc.ConnectionImpl.getInstance( host(props), port(props), props, database(props), url); return newConn; } catch (SQLException sqlEx) { ..... throw sqlEx; } catch (Exception ex) { ....... throw sqlEx; } } }
java.sql.DriverManager类
public class DriverManager { public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException { ....... registeredDrivers.addIfAbsent(new DriverInfo(driver)); ..... } private static Connection getConnection( String url, java.util.Properties info, Class<?> caller) throws SQLException { ....... for(DriverInfo aDriver : registeredDrivers) { // If the caller does not have permission to load the driver then // skip it. if(isDriverAllowed(aDriver.driver, callerCL)) { try { //此处进行了回调 Connection con = aDriver.driver.connect(url, info); ..... } }
相关文章推荐
- java设计模式——桥接模式(Bridge Pattern)
- java设计模式(九)——桥接模式(Bridge)
- 浅谈Java设计模式(十)桥接模式(Bridge)
- Java开发中的23种设计模式之十:桥接模式(Bridge)
- 浅谈JAVA设计模式之——桥接模式(Bridge)
- java设计模式之十桥接模式(Bridge)
- Java设计模式 - Bridge(桥接模式)
- Java设计模式——桥接模式(Bridge Pattern)
- java设计模式10——桥接模式(Bridge)
- Java设计模式(三)Adapter(适配器),Bridge(桥接)
- 设计模式学习笔记(八)——Bridge桥接模式
- 设计模式-Bridge(桥接模式)
- 设计模式——桥接模式(bridge)
- 学习:java设计模式—Bridge模式
- 设计模式之(十)桥接模式Bridge
- 步步为营 .NET 设计模式学习笔记 十三、Bridge (桥接模式)
- java bridge设计模式
- 设计模式之(十)桥接模式Bridge
- 设计模式解析(第二版)笔记5 Bridge 桥接模式
- 设计模式-桥接模式(Bridge Pattern)