彻底整明白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.