如何重构
DAO
模式
本文是在刘晓涛老师布置的课后作业,再由T10班级邓延课后总结而成。采取逐步重构的方法。版权有刘晓涛与邓延共有,转载需保留出处!
一、前言
本文的目的是将一个获取数据库连接的普通类重构成DAO+Abstract Factory模式。
二、设计初衷
使用数据访问对象(DAO,Data Access Object)模式来抽象和封装所有对数据源的访问。DAO管理着与数据源的连接以便检索和存储数据。可以降低商业逻辑层和数据访问层的耦合度,提高应用的可维护性和可移植性。
由于底层数据源实现变化时,DAO向客户端提供的接口不会变化,所有该模式允许DAO调整到不同的存储模式,而不会影响其客户端或者业务组件。显然,DAO充当了组件和数据源之间的适配器。
三、重构
首先,创建一个获取数据库连接的普通类:
DAOClient.java
import
java.sql.*;
public
class
DAOClient {
public
static
void
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.*;
public
class
DAOClient {
public
static
void
main( String[] args ) {
Connection conn = getConnection();
System.
out
.println( conn.toString() );
}
/**
*
得到一个
Connection
对象
*
@return
java.sql.Connection
*/
private
static
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.*;
public
class
OracleDAOFactory {
private
OracleDAOFactory() {}
/**
*
返回一个
OracleDAOFactory
对象
*
@return
OracleDAOFactory
类型对象
*/
public
static
OracleDAOFactory newInstance() {
return
new
OracleDAOFactory();
}
/**
*
得到一个
Connection
对象
*
@return
java.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 {
public
static
void
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;
public
class
OracleDAOFactory {
private
static
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
对象
*
@return
OracleDAOFactory
类型对象
*/
public
static
OracleDAOFactory newInstance() {
return
new
OracleDAOFactory();
}
/**
*
得到一个
Connection
对象
*
@return
java.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;
public
abstract
class
DAOFactory {
public
static
final
int
ORACLE
= 1;
public
static
final
int
SQLSERVER
= 2;
public
static
final
int
MYSQL
= 3;
public abstract Connection getConnection();
public
static
DAOFactory getDAOFactory(
int
dbType ) {
switch
( dbType ) {
case
ORACLE
:
return
OracleDAOFactory.newInstance();
case
SQLSERVER
:
return
SqlDAOFactory.newInstance();
case
MYSQL
:
return
MySqlDAOFactory.newInstance();
default
:
return
null
;
}
}
}
|
SqlDAOFactory.java
import
java.io.IOException;
import
java.sql.Connection;
import
java.sql.DriverManager;
import
java.sql.SQLException;
import
java.util.Properties;
public
class
SqlDAOFactory
extends
DAOFactory {
private
static
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
对象
*
@return
SqlDAOFactory
类型对象
*/
public
static
SqlDAOFactory newInstance() {
return
new
SqlDAOFactory();
}
/**
*
得到一个
Connection
对象
*
@return
java.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;
public
class
MySqlDAOFactory
extends
DAOFactory {
private
static
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
对象
*
@return
MySqlDAOFactory
类型对象
*/
public
static
MySqlDAOFactory newInstance() {
return
new
MySqlDAOFactory();
}
/**
*
得到一个
Connection
对象
*
@return
java.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
);
|