Currently I am using struts2 Framework for my work's project, and while designing my DAO classes I have a question in my mind to improve on the design patterns.
On my search function, I have 3 kinds of search
- search with one parameter, and the other,
- search with multiple parameters,
- search without parameters.
My question is, what is the best way to do the DAO method?
in my struts2 method, I'm having
public String execute() {
//assuming these are passed in from JSP
if ("searchByAnId".equals(paramSearch))
{
List<DTO> datalist = this.someDao.implementList(theIdParam);
} else if("searchByAnOtherParam".equals(paramSearch))
{
List<DTO> datalist = this.someDao.implementAnotherList(param1, param2, param3, param4)
// more params
} else
{
List<DTO> datalist = this.someDao.implementListAll();
}
return "success";
}
I was reading on Design Patterns such as Factory methods, Decorator methods, Observer method, but I wasn't sure which one is the most appropriate ones (or anything else without 3rd party plugin) that suits this?
I usually tend to create a basic dao interface with the definitions of methods common to all my domain entities, such as:
// marker interface
public interface DomainEntity extends Serializable { }
// common dao methods
public interface DAO<T extends DomainEntity> {
public T findById(Long id);
public List<T> findAll();
public T save(T entity);
public boolean update(T entity);
public boolean delete(T entity);
}
And then provide one or more implementations based on my requirements:
// implementation of common dao methods using JPA
public class JpaDAO<T> implements DAO<T> {
private EntityManager em;
public JpaDao(EntityManager em) { this.em = em; }
// Default implementations using JPA...
}
// implementation of common dao methods using JDBC
public class JdbcDAO<T> implements DAO<T> {
private Connection conn;
public JdbcDao(Connection conn) { this.conn = conn; }
// Default implementations using JDBC
}
Now, assuming i have the following person class:
public class Person implements DomainEntity {
private Long id;
private String firstName;
private String lastName;
// getters/setters...
}
I first define a generic PersonDAO interface like so:
public interface PersonDAO implements DAO<Person> {
public List<Person> findByFirstName(String name);
public List<Person> findByLastName(String name);
}
Note that in my specific entity dao interface above, i have included only the extra methods which are specific to my domain entity. Common methods are inherited by the super interface and are parameterised to my domain entity using generics.
Now the last remaining thing is to define different implementations of my entity specific methods, like so:
package mypackage.daos.jpa;
public class PersonDAOImpl extends JpaDAO<Person> implements PersonDAO {
// here i implement only the entity specific dao methods
// defined in the last interface.
}
If i also need to provide an alternative DAO implementation (say based on jdbc instead of JPA), its as easy as creating a second class (preferably in a separate package):
package mypackage.daos.jdbc;
public class PersonDAOImpl extends JdbcDAO<Person> implements PersonDAO {
// again i only implement the entity specific DAO methods since
// defaults have been implemented in the super class...
}
The nice thing about this is that you can switch implementations without the calling code to get affected by that:
// a service class that uses my dao
public class PersonService {
private PersonDAO dao;
public PersonService(PersonDAO dao) { this.dao = dao }
public void doSomethingUseful() {
// use the dao here...
}
}
Typically, the proper dao implementation (jdbc or jpa) would be injected via the constructor during service creation. Of course you can have only one implementation if you like (i.e. jpa).