For our purposes, we will look at what is required to accomplish the first two
tiers, but for transaction and connection management, you will need to refer to
chapter 7, and go from there.
Separating interface from implementation
The reason you want to separate your DAO into an interface and an implementa-
tion is twofold. First, you want to be able to replace the implementation if you
have to support a different type of data access. Second, separation makes testing
much simpler and faster because you can plug in a mock DAO instead of working
with the database.
If you use an IDE , you may think that this is going to be the easiest part of the proc-
ess. With most development environments, you have a refactoring tool to extract an
interface from the class. However, that is only a small part of the process.
If you are just getting started with the DAO pattern, it is likely that your inter-
face is exposing classes specific to JDBC , i BATIS , or some other tool for dealing
with your database. That is the part of the interface that is more difficult to man-
age. This creates a problem because it binds more of your application to the data
access implementation than just the DAO . Although it is not a huge difficulty, it is
not a trivial matter either.
Changing code that uses a result set to use a collection (such as a List of beans)
is straightforward, but as with any change, it will require testing, and depending
on where the code is located in your application, the process can be challenging.
For example, if you have a web application that uses a “Fast Lane Reader” pattern
to provide lightweight reporting over large data sets, your JDBC code may interact
directly with the view layer. This can be very difficult to test, because anything
requiring human interaction takes more time. In addition, it may be difficult to
rewrite in a way that performs as well as the original. One solution is to write the
code using callbacks to speed up the data access (so, in this example, you may
want to consider a RowHandler that responds to view requests for data).
Changing applications that directly access the SQL Map API to access a more
encapsulated API is a reasonably trivial matter. For example, if you are developing
a class that calls queryForList() on a SqlMapClient object, you simply need to
refactor that call into your DAO class, and then return the List object from it so
that your data consumer only talks to your DAO .
Decoupling and creating a factory
So, now that we have separated the interface and implementation, we do not want
to introduce both of those into our classes that use the DAO , because instead of