彻底整明白DAO模式
(from:http://www.hackhome.com/2005/1-23/19470630752.shtml)
很多的J2EE应用程序需 是各不相同的,并且用来访 序要在不同的持久性存储间 |
要使用持久性数据(数据库、文 问这些不同的持久性存储机制的 迁移,这些访问特定持久存储层 |
件等)。不同的程序,持久性存储 API也有很大的不同。如果应用程 的代码将面临重写。 |
如何解决这个问题?且看"DAO模式" |
数据访问对象(Data Acess Object) 模式 |
一.环境 |
根据数据源不同,数据 件等等)和供应商实现不同 |
访问也不同。根据存储的类型( ,持久性存储(比如数据库)的访 |
关系数据库、面向对象数据库、文 问差别也很大。 |
二.问题 |
许多真是的J2EE应用程 存储是使用不同的机制实现 同。 |
序需要在一定程度上使用持久性 的,并且用来访问这些不同的持 |
数据。对于许多应用程序,持久性 久性存储机制的API也有很大的不 |
比如,应用程序使用实体bean(这里 RDBMS的耦合)的分布式组件来表示持久性 管理系统(RDBMS)中的数据,这些组件中 源实现之间的紧密耦合。组件中这类代码 据源将变得非常麻烦和困难。当数据源变 据源。 |
应该是指BMP的bean,CMP的bean已大大降低了与 数据,或者使用JDBC API来访问驻留在某关系数据库 包含连接性性和数据访问代码会引入这些组件与数据 依赖性使应用程序从某种数据源迁移到其他种类的数 化时,组件也需要改变,以便于能够处理新类型的数 |
(举个例子来说,我们UPTEL系统是使 ,这些JDBC API与SQL语句散布在系统中 迁移到INFORMIX,就面临重写数据库连接 |
用JDBC API对 ORACLE数据库进行连接和数据访问的 ,当我们需要将UPTEL迁移到其他RDBMS时,比如曾经 和访问数据的模块。) |
三.作用力 |
1.诸如bean管理的实体 检索数据,以及进行数据存 |
bean、会话bean、servlet等组 储等操作。 |
件往往需要从持久性存储数据源中 |
2.根据产品供应商的不同,持久性存 类型不同也有差别,这样存在以下缺点, |
储API差别也很大,这些API和其能力同样根据存储的 即访问这些独立系统的API很不统一。 |
3.组件需要透明于实际 同存储类型和不同数据源类 |
的持久性存储或者数据源实现, 型的更容易的移植性。 |
以便于提供到不同供应商产品、不 |
四.解决方案 |
使用数据访问对象(DAO 连接以便检索和存储数据。 |
)模式来抽象和封装所有对数据 |
源的访问。DAO管理着与数据源的 |
DAO实现了用来操作数 业务组件为其客户端使用DA 于当低层数据源实现变化时 不同的存储模式,而不会影 适配器。 |
据源的访问机制。数据源可以时 O提供更简单的接口。DAO完全向 ,DAO向客户端提供的接口不会 响其客户端或者业务组件。重要 |
RDBMS,LDAP,File等。依赖于DAO的 客户端隐藏了数据源实现细节。由 变化,所有该模式允许DAO调整到 的是,DAO充当组件和数据源之间的 |
(按照这个理论,如果我们UPTEL系统 个RDBMS了。梦想总是很完美的,且看看D |
使用了DAO模式,就可以无缝的从ORACLE迁移到任何一 AO模式如何实现) |
1.结构,图1是表示DAO模式中各种关系的类图。 |
此主题相关图片如下: |
|
2.参与者和职责 |
1)BusinessObject(业务对象) |
代表数据客户端。正是该对象需要访问数据源以获取和存储数据。 |
2)DataAccessObject(数据访问对象) |
是该模式的主要对象。DataAccessOb 保证对数据源的透明访问。BusinessObje DataAccessObject。 |
ject抽取该BusinessObject的低层数据访问实现,以 ct也可以把数据加载和存储操作委托给 |
3)DataSource(数据源) |
代表数据源实现。数据 |
源可以是各RDBMSR数据库,OODB |
MS,XML文件等等。 |
4)valueObject(值对象) |
代表用做数据携带着的 。 |
值对象。DataAccessObject可以 |
使用值对象来把数据返回给客户端 |
DataAccessObject也许会接受来自于 于值对象中来传递。 |
客户端的数据,其中这些用于更新数据源的数据存放 |
3.策略 |
1).自动DAO代码产生策略 |
因为每个BusinessObje 层实现(比如RDBMS中的表) 写与应用程序有馆的代码生 就完了,最多自己写几个Ad 应用程序需要的所有DAO代 |
ct对应于一个特殊的DAO,因此有 之间的关系(映射)。一点这些关 成的简单工具了(什么?自己写GP apter,牛人就是不同,啥都要自 码。 |
可能建立BusinessObject,DAO和低 系(映射)已经建立,我们就可以编 程序?用ORM的附带工具自动生成不 己写...),其中的工具可以产生该 |
如果DAO需求很复杂, 的关系映射(这里指的是前 ORM工具有很多:Hibernate, |
我们可以采用第三方工具,其中 面提到的ORM工具,全称是Objec OJB,Torque,TopLink等等)。 |
这些工具提供对象到RDBMS数据库 t Relation Mapping,目前成熟的 |
这些工具通常包含GUI工具来把业务 。一旦这些映射完成,这些工具会自动地 缓冲、查询缓冲、与应用程序集成,以及 |
对象映射到持久性存储对象,并且因而定义中间DAO 生成代码,并且也许会提供其他增值功能,比如结果 与其他第三方产品(比如分布式缓冲)地继承,等等。 |
(增值服务:Torque提 ,OJB提供JDO API、OMDB AP |
供了结果缓冲,Hibernate提供了 I) |
对Oracle数据库SQL指令的优化 |
2).数据访问对象的工厂策略 |
通过调整抽象工厂和工厂方法模式,DAO模式可以达到很高的灵活度。 |
当低层存储不会随着实现变化而变化 产生应用程序需要的大量DAO。图2是这种 |
时,该策略可以使用工厂方法模式来实现该策略。以 情况下的类图。 |
此主题相关图片如下: |
|
当低层存储随着实现变化而变化时,该策略可以使用抽象工厂方法模式而实现。 |
图3是这种情况下的类图。 |
此主题相关图片如下: |
|
5.结果 |
1).启用透明性 |
业务对象可以是使用数 是实现被隐藏在DAO的内部 |
据源,而无须了解该数据源实现 。 |
的具体细节。访问是透明的,原因 |
2).启用更容易的迁移 |
DAO层使应用程序更加 现。因而,该迁移只涉及对 个低层存储实现提供一个具 程序提供一个新的工厂实现 |
容易地迁移到一个不同的数据库 DAO层的变化。更进一步说,如 体工厂实现。在这种情况下,迁 。 |
实现。业务对象不了解低层数据实 果使用工厂策略,则有可能为每一 移到不同的迁移实现意味着给应用 |
3).减少业务对象中代码复杂度 |
由于DAO管理所有的数据访问复杂性 代码。所有与实现有关的代码(比如sql语 样做提高了代码的可读性,已经代码生产 |
,它可以简化业务对象和其他使用DAO的客户端中的 句)都被包含在DAO中,而不是包含在业务对象中。这 效率。 |
4).把所有的数据访问集中到一个独立的层。 |
因为所有的数据访问操 实现与应用程序中的其他代 |
作现在被委托给DAO,所有单独的 码相隔离的。这种集中化使应用 |
数据访问层可以被看作把数据访问 程序更容易地维护和管理。 |
5).不适用于容器管理的持久性 |
由于EJB容器用容器管理的持久性(CM 性存储访问。使用容器管理的实体bean的 地提供该功能。然而,当需要组合使用CM |
P)来管理实体bean,该容器会自动地服务所有的持久 应用程序不需要DAO层,因为该应用程序服务器透明 P和BMP时,DAO仍旧有用处。 |
6).添加其他层 |
DAO会在数据客户端和数据源之间创 便于权衡该模式的好处。但是选择本方法 |
建其他的对象层,其中该数据源需要被设计和实现以 也会带来额外的开销。 |
7).需要类层次设计 |
在使用工厂策略时,我 层次。如果能够确保这种灵 。然而,在实现该工厂策略 厂。 |
们需要设计和实现具体工厂的层 活性,则有必要考虑这种额外的 时,你可以首先考虑工厂方法模 |
次,以及这些工厂产生的具体产品 工作。这样做会增加设计的复杂性 式,然后再根据需要过渡到抽象工 |
六.范例代码 |
1.实现数据访问对象模式 |
范例9-4时表示Custome CloudscapeCustomerDAO创 |
r信息的持久性对象的DAO范例代 建一个Customer值对象。 |
码。当findCustomer()被调用时, |
范例9-6是使用DAO的范例代码。 |
2.实现数据访问对象的工厂策略 |
1)使用工厂方法模式 |
2)使用抽象工厂模式 |
范例代码9-2是CloudscapeDAOFactory的范例代码。 |
范例代码9-3中的CustomerDAO接口为 所有具体DAO实现来实现的,比如Cloudsc SybaseCustomerDAO。Account和OrederDA |
Customer持久性对象定义了DAO方法,这些接口是被 apeCustomerDAO、OracleCustomerDAO、已经 O接口也与此类似。 |
Example 9.1 Abstract DAOFactory Class |
// Abstract class DAO Factory |
public abstract class DAOFactory { |
// List of DAO types supported b |
y the factory |
public static final int CLOUDSCAPE = 1; |
public static final int ORACLE = 2; |
public static final int SYBASE = 3; |
... |
// There will be a m |
ethod for each DAO that can |
be |
// created. The conc |
rete factories will have to |
// implement these methods. |
public abstract Cust |
omerDAO getCustomerDAO(); |
public abstract Acco |
untDAO getAccountDAO(); |
public abstract OrderDAO getOrderDAO(); |
... |
public static DAOFactory getDAOFactory( |
int whichFactory) { |
switch (whichFactory) { |
case CLOUDSCAPE: |
return new CloudscapeDAOFactory(); |
case ORACLE : |
return new OracleDAOFactory(); |
case SYBASE : |
return new SybaseDAOFactory(); |
... |
default : |
return null; |
} |
} |
} |
Example 9.2 Concrete |
DAOFactory Implementation f |
or Cloudscape |
// Cloudscape concrete DAO Facto |
ry implementation |
import java.sql.*; |
public class Cloudsc |
apeDAOFactory extends DAOFac |
tory { |
public static final String DRIVER= |
"COM.cloudscape.core.RmiJdbcDriver"; |
public static final String DBURL= |
"jdbc:cloudscape:rmi |
://localhost:1099/CoreJ2EEDB |
"; |
// method to create Cloudscape c |
onnections |
public static Connec |
tion createConnection() { |
// Use DRIVER and DBURL to creat |
e a connection |
// Recommend connect |
ion pool implementation/usag |
e |
} |
public CustomerDAO getCustomerDAO() { |
// CloudscapeCustome |
rDAO implements CustomerDAO |
return new CloudscapeCustomerDAO(); |
} |
public AccountDAO getAccountDAO() { |
// CloudscapeAccountDAO implemen |
ts AccountDAO |
return new CloudscapeAccountDAO(); |
} |
public OrderDAO getOrderDAO() { |
// CloudscapeOrderDA |
O implements OrderDAO |
return new CloudscapeOrderDAO(); |
} |
... |
} |
Example 9.3 Base DAO Interface f |
or Customer |
// Interface that all CustomerDA |
Os must support |
public interface CustomerDAO { |
public int insertCustomer(...); |
public boolean deleteCustomer(...); |
public Customer findCustomer(...); |
public boolean updateCustomer(...); |
public RowSet selectCustomersRS(...); |
public Collection se |
lectCustomersVO(...); |
... |
} |
Example 9.4 Cloudscape DAO Imple |
mentation for Customer |
// CloudscapeCustomerDAO impleme |
ntation of the |
// CustomerDAO interface. This c |
lass can contain all |
// Cloudscape specific code and |
SQL statements. |
// The client is thus shielded f |
rom knowing |
// these implementation details. |
import java.sql.*; |
public class Cloudsc |
apeCustomerDAO implements |
CustomerDAO { |
public CloudscapeCustomerDAO() { |
// initialization |
} |
// The following methods can use |
// CloudscapeDAOFact |
ory.createConnection() |
// to get a connection as required |
public int insertCustomer(...) { |
// Implement insert customer here. |
// Return newly created customer number |
// or a -1 on error |
} |
public boolean deleteCustomer(...) { |
// Implement delete customer here |
// Return true on success, false |
on failure |
} |
public Customer findCustomer(...) { |
// Implement find a customer her |
e using supplied |
// argument values as search criteria |
// Return a value object if found, |
// return null on error or if not found |
} |
public boolean updateCustomer(...) { |
// implement update record here |
using data |
// from the customerData value object |
// Return true on success, false |
on failure or |
// error |
} |
public RowSet selectCustomersRS(...) { |
// implement search |
customers here using the |
// supplied criteria. |
// Return a RowSet. |
} |
public Collection selectCustomer |
sVO(...) { |
// implement search customers he |
re using the |
// supplied criteria. |
// Alternatively, im |
plement to return a Collecti |
on |
// of value objects. |
} |
... |
} |
Example 9.5 Customer value Object |
public class Customer implements |
java.io.Serializable { |
// member variables |
int CustomerNumber; |
String name; |
String streetAddress; |
String city; |
... |
// getter and setter methods... |
... |
} |
Example 9.6 Using a |
DAO and DAO Factory ?Client |
Code |
... |
// create the required DAO Factory |
DAOFactory cloudscapeFactory = |
DAOFactory.getDAOFactory(DAOFact |
ory.DAOCLOUDSCAPE); |
// Create a DAO |
CustomerDAO custDAO = |
cloudscapeFactory.getCustomerDAO(); |
// create a new customer |
int newCustNo = custDAO.insertCu |
stomer(...); |
// Find a customer o |
bject. Get the value object. |
Customer cust = custDAO.findCust |
omer(...); |
// modify the values in the valu |
e object. |
cust.setAddress(...); |
cust.setEmail(...); |
// update the custom |
er object using the DAO |
custDAO.updateCustomer(cust); |
// delete a customer object |
custDAO.deleteCustomer(...); |
// select all customers in the s |
ame city |
Customer criteria=new Customer(); |
criteria.setCity("广州"); |
Collection customersList = |
custDAO.selectCustomersVO(criteria); |
// returns customers |
List - collection of Custome |
r |
// value objects. iterate throug |
h this collection to |
// get values. |