您的位置:首页 > 编程语言 > Java开发

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类的代码都必须类似如下:

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);  
         .....  
    }  
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: