|
J2EE Blueprints Design Pattern
Data Access Object (DAO)
|
|
|
|
|
Data Access Object (DAO)
|
|
|
Creates flexible information resources by encapsulating and hiding
their access mechanisms. Especially useful for encapsulating the SQL
for Bean Managed Persistence. Decouples a resource class's usage
from how it is represented internally or persistently.
|
|
|
Provide flexible, extensible access to data and other resources
|
|
|
Object Structural
|
|
|
Systems that rely on specific features of underlying resources,
such as a particular vendor's database, tie together business
logic and data access mechanisms. The result is often limited
portability and undesirable vendor lock-in. As these underlying
products become obsolete, or as superior solutions appear, systems
tied to older versions of products can be difficult to upgrade or
replatform. And enterprise bean component vendors want to avoid
tying their business logic components to a particular vendor, so
they can serve the broadest possible segment of the market.
The Data Access Object (or DAO) pattern separates the interface to a system
resource from the underlying strategy used to access that
resource. The Java Pet Store uses the DAO pattern
both to achieve database vendor independence, and to represent XML
data sources as objects.
Each enterprise Bean that accesses a back-end resource in the Java
Pet Store application has an associated DAO class, which defines
an abstract API of operations on the resource. This abstract API
makes no reference to how the resource is implemented. The DAO
simply has to know how to load itself from persistent store based
on some identity information (a primary key, a filename, etc.),
how to store itself, and so on. For example, an enterprise bean
uses data it obtains from the DAO, not directly from the
database. In this way, the enterprise bean defers its persistence
mechanism to the DAO, allowing it to concentrate entirely on
implementing business methods.
A Data Access Object class provides resource functionality for a
particular resource, and implemented for a particular persistence
mechanism. For example, the Java Pet Store uses the class
CatalogDAO to encapsulate the database code that accesses both
single and lists of Categories, Products and Items. The fact that
CatalogDAO is implemented in terms of JDBC is hidden from the rest
of the application. Reimplementing CatalogDAO for a different
persistence mechanism (to use stateful entity beans, for example,)
would have little or no impact on the classes that
use CatalogDAO, since only the implementation, not the interface,
would change. Each potential alternate implementation of
CatalogDAO would access data for the items in the Catalog in its
own way, while presenting the same API to the enterprise bean.
The DAO class is not limited to representing objects stored in a
database. The Java Pet Store also uses the DAO pattern to
represent XML data sources as objects. Instead of manipulating an
in-memory representation of an XML document, the Java Pet Store
represents the screen flow in the application as an instance of
class ScreenFlowXmlDAO. If the designers (or maintainers) were to
decide to change the application to store screen flow information
in the database, instead of in an XML file, they would need only
implement a single new class (ScreenFlowCloudscapeDAO, for
example). The code that uses ScreenFlowXmlDao would remain
unchanged, but the data would come from the database via the new
class. Likewise, a new concrete subclass of OrderDAO (say, for
example, OrderDAORemoteXml,) could access a remote XML data source
to get the underlying data for instance of an OrderEJB.
|
|
|
Use Data Access Object:
- to separate resource interface from resource implementation
- whenever the resource implementation mechanism might change
- to support selecting resource implementation method at
deploy time
|
|
|
 |
Figure 1. UML Diagram for Data Access Object.
|
|
|
|
|
- abstracts business operations
- avoids making reference to the external resources it
uses
|
|
- an arbitrary class may also access DAOs
|
|
- abstracts operations on a resource
- provides a standardized API for accessing and manipulating data
of a particular type
|
|
- provides resource data persistence and retrieval by
way of an arbitrary API
|
|
|
|
|
- Uses a DataAccessObject for standardized, opaque access
to a Resource
|
|
- Can also use a DataAccessObject for standardized, opaque
access to a Resource
|
|
- provides an abstract API for the resource
- provides the standard way for EJB's or NonEJB's to
access and manipulate a particular type of Resource
|
|
- provides data to ConcreteDataObject
|
|
|
|
Potential consequences of using the Data Access Object
pattern include:
-
Greater deployment flexibility. Data Access
Objects present resources as DAOs. An Abstract Factory can use
deployment configuration data to select a Data Access Object's
class and initialization data at runtime, automatically
configuring the application to use a particular database type.
In fact, this is precisely how the OrderDAO class works in the
Java Pet Store. The application code accesses Order data
through the abstract class OrderDAO , implemented
by a concrete subclass of OrderDAO
(OrderDAOOracle , OrderDAOSybase , or
OrderDAOCS ). The application gets the
OrderDAO by calling the public static method
OrderDAOFactory.getDAO() , which constructs an
appropriate OrderDAO subclass based on the
database product name of the JDBC data source (as reported by
JNDI).
-
Resource vendor independence. Coding
business logic with vendor-specific APIs locks components into
that vendor. The layer of indirection provided by the DAO
pattern centralizes vendor-specific code in a class or several
classes, where it can be replaced if necessary or desirable.
-
Resource implementation independence. The
question of vendor lock-in aside, similar types of resources
are often available in various formats through various access
methods. For example, persistent data store can be
implemented by a relational database, an object database, flat
files in a filesystem, interaction with a remote persistence
server, and so on. The DAO pattern allows the designer to
focus on the behavior of application objects, and separate out
data access mechanism details.
-
Easier migration to Container Managed
Persistence. Data Access Object encapsulates persistence
logic, separating it from Bean business logic, and facilitating
migration from Bean Managed Persistence (BMP) to Container
Managed Persistence (CMP). Furthermore, separate
ConcreteDataObject classes can implement either BMP or CMP, which
can be selected as appropriate to the implementation context.
While reimplementation of the DAO classes will still be necessary,
the code that needs are implementing will be encapsulated in one place.
-
Enhanced extensibility. New resource types
are easy to add, requiring only a new ConcreteDataObject layer for
the resource type, plus integration of that layer into the
existing framework.
-
More classes and objects. The Data Access
Object pattern adds a level of indirection to data access,
increasing the number of classes and objects in the system and
making the code slightly less clear. The memory impact of
these additional classes and objects can be minimized by
techniques such as caching, as well as avoiding redundant
copies of data in the enterprise bean.
|
|
|
Here are some issues to consider when implementing the Data Access
Object pattern:
-
Automatically generating the ConcreteDataObject
layer facilitates maintenance, extensibility, evolvability and
portability. Automatically-generated DAO layer code
facilitates maintenance, primarily because generated code tends
to have fewer flaws than handwritten code. In systems with
large numbers of DAO classes, generation can be the only
practical solution. Portability is enhanced across resource
types as well as platforms, because resource type and
platform-specific functionality can be written into the
generation tool. This solution also enhances extensibility,
since new functionality can be added to entire groups of DAO
classes by modifying the code generation.
When Data Access Object is used to abstract database resources,
the greatest benefit is often evolvability. Database schema
changes almost always have an impact on code. If the DAO layer
is generated from the database schema, database schema changes
can be reflected in code simply by regenerating. Of course,
this does not address the question of adding or modifying the
functionality the new schema is meant to support, but it does
automate code changes (such as adding or deleting field
accessors) which are totally derivable from schema. Functionality
not derivable from database metadata can be implemented in
subclasses of the DAO classes, to isolate the "custom" behavior
from generated behavior.
Software development organizations can develop a standardized,
database DAO generation toolset, reusable across projects. Such
a toolset, well-understood by its users, would encourage coding
consistency across projects, while allowing selection of the
most appropriate resource implementation for the project.
-
Consider introducing an abstract base class.
If there are several potential implementations of the same
DAO class, it may be useful to create an abstract DAO class,
which those implementations then extend. Functionality common
to the implementations can be implemented in the abstract base class,
while implementation-specific code is placed in the concrete
subclasses.
The Java Pet Store uses this technique (as described above)
for the OrderDAO class. OrderDAO is an abstract DAO class,
which implements functionality common to all Order subclasses.
The Order subclasses implement functionality exclusively
related to a single database type. At runtime, the
application selects the appropriate subclass of OrderDAO to
access the configured database.
-
An abstract DAO class does not necessarily imply a
least common denominator solution. While it is true
that abstraction may impede efficiency by hiding
implementation details that might otherwise be used for
optimization, it's usually possible to design around a "least
common denominator" limitation. An optimization that is
inaccessible from the abstract DAO layer can usually be made
accessible by moving the functionality into the DAO API. DAO
subclasses that cannot perform the optimization can either
simulate the operation (possibly suboptimally), or treat to
request as an error condition which the caller must then
handle.
-
Data Access Objects can be accessed by both EJBs
and objects of arbitrary class. While DAO classes are
useful abstractions for implementing EJBs in a
database-independent way, they can also be used by any class
to access resources. For example, the Java Pet Store Catalog
class accesses DAOs directly from the application's web tier
of the application, and the application screen flow comes from
a DAO that is backed by an XML file.
-
Consider making the DAO an interface. If
none of the operations on a DAO have meaningful default
implementations, a DAO may be defined more flexibly as an
interface instead of as a concrete class or abstract base
class. When using an interface, default implementations of an
DAO interface can be reside in a "support" class, which is a
DAO whose methods implement the interface, but either do
nothing, or have some reasonable default behavior. Programmers
subclass the support class, overridding only those methods
necessary to implement the desired functionality.
-
The Data Access Object pattern might complicate
transactional logic.Different resource implementations
may have very different transactional behaviors. As a result,
it may be difficult to decide where (in an abstract API) to
put the logic for transactional operations on the underlying
resource. One possible solution to this problem might be
introduce an opaque "helper" class, which encapsulates
information the DAO class needs to perform its transactional
functions. This class will encapsulate transaction state in a
way comprehensible to the DAO class.
-
Container Managed Persistence may make Data Access
Object unnecessary. Container Managed Persistence
already abstracts the data persistence mechanism out of the
enterprise bean logic, making DAO superfluous.
|
|
|
An example of Data Access Object using an Abstract Factory to select an
underlying database resource:
OrderDAOFactory.java
OrderDAO.java
OrderDAOCS.java
OrderDAOOracle.java
OrderDAOSybase.java
An example of a concrete Data Access Object representing an underlying,
non-database resource (an XML file):
ScreenFlowXmlDAO.java
|
|
|
Strategy (GoF)
Policy
Adapter (GoF)
Wrapper
|