http://www.mldn.cn/articleview/2008-6-23/article_view_3195.htm
一、前言
本文的目的是将一个获取数据库连接的普通类重构成DAO+Abstract Factory模式。
二、设计初衷
使用数据访问对象(DAO,Data Access Object)模式来抽象和封装所有对数据源的访问。DAO管理着与数据源的连接以便检索和存储数据。可以降低商业逻辑层和数据访问层的耦合度,提高应用的可维护性和可移植性。
由于底层数据源实现变化时,DAO向客户端提供的接口不会变化,所有该模式允许DAO调整到不同的存储模式,而不会影响其客户端或者业务组件。显然,DAO充当了组件和数据源之间的适配器。
三、重构
首先,创建一个获取数据库连接的普通类:
DAOClient.java
import java.sql.*;
publicclass DAOClient {
publicstaticvoid main( String[] args ) {
try {
//For Oracle
Class.forName( "oracle.jdbc.driver.OracleDriver" );
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:dy", "scott", "tiger" );
System.out.println( conn.toString() );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
再将这段代码封装到一个getConnection()方法中以便其它的地方调用:
import java.sql.*;
publicclass DAOClient {
publicstaticvoid main( String[] args ) {
Connection conn = getConnection();
System.out.println( conn.toString() );
}
/**
*得到一个Connection对象
*@returnjava.sql.Connection
*/
privatestatic Connection getConnection() {
Connection conn = null;
try {
//For Oracle
Class.forName( "oracle.jdbc.driver.OracleDriver" );
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:dy", "scott", "tiger" );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
} catch ( SQLException e ) {
e.printStackTrace();
}
return conn;
}
}
再将此方法定义到针对Oracle的工厂类中:
OracleDAOFactory.java
import java.sql.*;
publicclass OracleDAOFactory {
private OracleDAOFactory() {}
/**
*返回一个OracleDAOFactory对象
*@returnOracleDAOFactory类型对象
*/
publicstatic OracleDAOFactory newInstance() {
returnnew OracleDAOFactory();
}
/**
*得到一个Connection对象
*@returnjava.sql.Connection
*/
public Connection getConnection() {
Connection conn = null;
try {
//For Oracle
Class.forName( "oracle.jdbc.driver.OracleDriver" );
conn = DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:dy", "scott", "tiger" );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
} catch ( SQLException e ) {
e.printStackTrace();
}
return conn;
}
}
此时,DAOClient.java这个测试类的代码应修改为:
import java.sql.*;
public class DAOClient {
publicstaticvoid main( String[] args ) {
Connection conn = OracleDAOFactory.newInstance().getConnection();
System.out.println( conn.toString() );
}
}
考虑:通常,数据库服务器、数据库名、数据库用户、密码等应该从配置文件中获取。因此,修改Oracle的工厂类:
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
publicclass OracleDAOFactory {
privatestatic Properties prop = new Properties();
static {
try {
prop.load( OracleDAOFactory.class
.getResourceAsStream( "config.properties" ) );
} catch ( IOException e ) {
System.out.println( "File:config.properties no find,PLS check out!" );
e.printStackTrace();
}
}
private String CONNECTION_SERVER_NAME = prop
.getProperty( "oracle_server_name" );
private String CONNECTION_DRIVER = prop.getProperty( "oracle_conn_driver" );
private String CONNECTION_DBINSTANCE = prop
.getProperty( "oracle_dbInstance" );
private String CONNECTION_USER = prop.getProperty( "oracle_conn_user" );
private String CONNECTION_PWD = prop.getProperty( "oracle_conn_pwd" );
private String CONNECTION_URL = "jdbc:oracle:thin:@"
+ CONNECTION_SERVER_NAME + ":1521:" + CONNECTION_DBINSTANCE;
private OracleDAOFactory() {}
/**
*返回一个OracleDAOFactory对象
*@returnOracleDAOFactory类型对象
*/
publicstatic OracleDAOFactory newInstance() {
returnnew OracleDAOFactory();
}
/**
*得到一个Connection对象
*@returnjava.sql.Connection
*/
public Connection getConnection() {
Connection conn = null;
try {
Class.forName( CONNECTION_DRIVER );
conn = DriverManager.getConnection(
CONNECTION_URL, CONNECTION_USER, CONNECTION_PWD );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
} catch ( SQLException e ) {
e.printStackTrace();
}
return conn;
}
}
添加配置文件config.properties:
oracle_server_name=localhost
oracle_conn_driver=oracle.jdbc.driver.OracleDriver
oracle_dbInstance=dy
oracle_conn_user=scott
oracle_conn_pwd=tiger
继续考虑,客户端在获取数据库连接时使用的是针对Oracle的数据库的工厂,但如果数据库变化了,那么客户端的代码还是要改变。因此,可以定义一个DAOFactory类,定义了一个抽象方法:getConnection()用于获取数据库连接,还有一个getDAOFactory()方法,根据参数dbType的值,返回不同的DAOFactory。
DAOFactory.java
import java.sql.Connection;
publicabstractclass DAOFactory {
publicstaticfinalintORACLE = 1;
publicstaticfinalintSQLSERVER = 2;
publicstaticfinalintMYSQL = 3;
public abstract Connection getConnection();
publicstatic DAOFactory getDAOFactory( int dbType ) {
switch( dbType ) {
caseORACLE:
return OracleDAOFactory.newInstance();
caseSQLSERVER:
return SqlDAOFactory.newInstance();
caseMYSQL:
return MySqlDAOFactory.newInstance();
default:
returnnull;
}
}
}
SqlDAOFactory.java
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
publicclass SqlDAOFactory extends DAOFactory {
privatestatic Properties prop = new Properties();
static {
try {
prop.load( OracleDAOFactory.class
.getResourceAsStream( "config.properties" ) );
} catch ( IOException e ) {
System.out.println( "File:config.properties no find,PLS check out!" );
e.printStackTrace();
}
}
private String CONNECTION_SERVER_NAME = prop
.getProperty( "sqlserver_server_name" );
private String CONNECTION_DRIVER = prop.getProperty( "sqlserver_conn_driver" );
private String CONNECTION_DBINSTANCE = prop
.getProperty( "sqlserver_dbInstance" );
private String CONNECTION_USER = prop.getProperty( "sqlserver_conn_user" );
private String CONNECTION_PWD = prop.getProperty( "sqlserver_conn_pwd" );
private String CONNECTION_URL = "jdbc:microsoft:sqlserver://"
+ CONNECTION_SERVER_NAME + ":1433;DatabaseName="
+ CONNECTION_DBINSTANCE;
private SqlDAOFactory() {}
/**
*返回一个SqlDAOFactory对象
*@returnSqlDAOFactory类型对象
*/
publicstatic SqlDAOFactory newInstance() {
returnnew SqlDAOFactory();
}
/**
*得到一个Connection对象
*@returnjava.sql.Connection
*/
public Connection getConnection() {
Connection conn = null;
try {
Class.forName( CONNECTION_DRIVER );
conn = DriverManager.getConnection(
CONNECTION_URL, CONNECTION_USER, CONNECTION_PWD );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
} catch ( SQLException e ) {
e.printStackTrace();
}
return conn;
}
}
MySqlDAPFactory.java
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
publicclass MySqlDAOFactory extends DAOFactory {
privatestatic Properties prop = new Properties();
static {
try {
prop.load( OracleDAOFactory.class
.getResourceAsStream( "config.properties" ) );
} catch ( IOException e ) {
System.out.println( "File:config.properties no find,PLS check out!" );
e.printStackTrace();
}
}
private String CONNECTION_SERVER_NAME = prop
.getProperty( "mysql_server_name" );
private String CONNECTION_DRIVER = prop.getProperty( "mysql_conn_driver" );
private String CONNECTION_DBINSTANCE = prop
.getProperty( "mysql_dbInstance" );
private String CONNECTION_USER = prop.getProperty( "mysql_conn_user" );
private String CONNECTION_PWD = prop.getProperty( "mysql_conn_pwd" );
private String CONNECTION_URL = "jdbc:mysql://"
+ CONNECTION_SERVER_NAME + ":3306/" + CONNECTION_DBINSTANCE
+ "?useUnicode=true&characterEncoding=UTF-8";
private MySqlDAOFactory() {}
/**
*返回一个MySqlDAOFactory对象
*@returnMySqlDAOFactory类型对象
*/
publicstatic MySqlDAOFactory newInstance() {
returnnew MySqlDAOFactory();
}
/**
*得到一个Connection对象
*@returnjava.sql.Connection
*/
public Connection getConnection() {
Connection conn = null;
try {
Class.forName( CONNECTION_DRIVER );
conn = DriverManager.getConnection(
CONNECTION_URL, CONNECTION_USER, CONNECTION_PWD );
} catch ( ClassNotFoundException e ) {
e.printStackTrace();
} catch ( SQLException e ) {
e.printStackTrace();
}
return conn;
}
}
修改config.properties配置文件:
#Oracle
oracle_server_name=localhost
oracle_conn_driver=oracle.jdbc.driver.OracleDriver
oracle_dbInstance=dy
oracle_conn_user=scott
oracle_conn_pwd=tiger
#SqlServer
sqlserver_server_name=localhost
sqlserver_conn_driver=com.microsoft.jdbc.sqlserver.SQLServerDriver
sqlserver_dbInstance=test
sqlserver_conn_user=sa
sqlserver_conn_pwd=sa
#MySql
mysql_server_name=localhost
mysql_conn_driver=com.mysql.jdbc.Driver
mysql_dbInstance=test
mysql_conn_user=root
mysql_conn_pwd=root
最后,修改客户端文件DAOClient.java代码:
import java.sql.*;
public class DAOClient {
public static void main( String[] args ) {
DAOFactory dao = DAOFactory.getDAOFactory( DAOFactory.ORACLE );
Connection conn = dao.getConnection();
System.out.println( conn.toString() );
}
}
通过这种DAO+(Abstract)Factory方式,在将程序迁移到其它数据库中时,在客户端程序中几乎不用做修改,唯一需要做的,就是在获得DAOFactory对象的时候,修改相应的参数,例如,迁移到MySql下的时候:
DAOFactory dao = DAOFactory.getDAOFactory( DAOFactory.MYSQL );