Java EE DAO / DTO(数据传输对象)设计模式

目前我正在为我的工作项目使用struts2 Framework,在设计我的DAO类时,我在脑海中有一个问题需要改进设计模式。

在我的搜索function上,我有3种搜索

  1. 用一个参数搜索,另一个参数,
  2. 搜索多个参数,
  3. 搜索没有参数。

我的问题是,DAO方法的最佳方法是什么?

在我的struts2方法中,我有

public String execute() { //assuming these are passed in from JSP if ("searchByAnId".equals(paramSearch)) { List datalist = this.someDao.implementList(theIdParam); } else if("searchByAnOtherParam".equals(paramSearch)) { List datalist = this.someDao.implementAnotherList(param1, param2, param3, param4) // more params } else { List datalist = this.someDao.implementListAll(); } return "success"; } 

我正在阅读设计模式,如工厂方法,装饰器方法,观察者方法,但我不确定哪一个是最适合的(或其他没有第三方插件的东西)适合这个?

我通常倾向于创建一个基本的dao接口,其中包含我所有域实体共有的方法定义,例如:

 // marker interface public interface DomainEntity extends Serializable { } // common dao methods public interface DAO { public T findById(Long id); public List findAll(); public T save(T entity); public boolean update(T entity); public boolean delete(T entity); } 

然后根据我的要求提供一个或多个实现:

 // implementation of common dao methods using JPA public class JpaDAO implements DAO { private EntityManager em; public JpaDao(EntityManager em) { this.em = em; } // Default implementations using JPA... } // implementation of common dao methods using JDBC public class JdbcDAO implements DAO { private Connection conn; public JdbcDao(Connection conn) { this.conn = conn; } // Default implementations using JDBC } 

现在,假设我有以下人员类:

 public class Person implements DomainEntity { private Long id; private String firstName; private String lastName; // getters/setters... } 

我首先定义一个通用的PersonDAO接口,如下所示:

 public interface PersonDAO implements DAO { public List findByFirstName(String name); public List findByLastName(String name); } 

请注意,在我上面的特定实体dao接口中,我只包含了特定于我的域实体的额外方法。 常用方法由超级接口inheritance,并使用generics参数化到我的域实体。

现在最后剩下的就是定义我的实体特定方法的不同实现,如下所示:

 package mypackage.daos.jpa; public class PersonDAOImpl extends JpaDAO implements PersonDAO { // here i implement only the entity specific dao methods // defined in the last interface. } 

如果我还需要提供替代的DAO实现(比如基于jdbc而不是JPA),那么就像创建第二个类(最好是在一个单独的包中)一样简单:

 package mypackage.daos.jdbc; public class PersonDAOImpl extends JdbcDAO implements PersonDAO { // again i only implement the entity specific DAO methods since // defaults have been implemented in the super class... } 

关于这一点的好处是你可以在没有调用代码的情况下切换实现,从而受到影响:

 // 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... } } 

通常,在服务创建期间,将通过构造函数注入正确的dao实现(jdbc或jpa)。 当然,如果你愿意,你只能有一个实现(即jpa)。