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

5
目前我在工作项目中使用Struts2框架,设计DAO类时我有一个问题,希望能够改进设计模式。
在我的搜索功能中,我有三种搜索方式:
1. 用一个参数进行搜索,另一个则不用;
2. 用多个参数进行搜索;
3. 不使用任何参数进行搜索。
我的问题是,如何最好地实现DAO方法?
在我的Struts2方法中,我有:
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";
}

我正在阅读有关设计模式的内容,例如工厂方法、装饰器方法和观察者方法,但我不确定哪种方法(或其他任何不使用第三方插件的方法)最适合此情况?


1
在我的项目中,我创建了一个SearchCriteria对象,其中包含DAO所属的表的列。然后您可以在此SearchCriteria对象中提供详细信息,并根据其进行DAO内的搜索。 - Atul
是的,我认为这方面没有特定的设计模式。 - Atul
1个回答

6

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

// 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);
}

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

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

现在,假设我有以下的人类(person class):
public class Person implements DomainEntity {
  private Long id;
  private String firstName;
  private String lastName;

  // getters/setters...
}

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

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

请注意,在我特定的实体DAO接口中,我只包含了与我的领域实体特定的额外方法。通用方法由超级接口继承,并使用泛型参数化为我的领域实体。
现在,最后一件事是定义不同的实现方式来实现我实体特定的方法,如下所示:
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.
}

如果我还需要提供另一种DAO实现(比如基于jdbc而不是JPA),那么创建第二个类就像轻而易举的事情,最好将它放在一个单独的包中:

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

这样做的好处是,您可以在不影响调用代码的情况下切换实现方式:
// 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)。


所以只是确认一下,“interface PersonDAO”和“DAO<Person>”之间的关系是什么?抱歉,我对设计模式不太熟悉... - prog rice bowl
接口DAO是一个类型参数化的接口,它定义了所有领域实体通用的DAO操作。接口PersonDAO(扩展DAO)包括特定于Person领域实体的操作。 - Lefteris Laskaridis
关于通用的PersonDao - 它不应该是implements,而应该是interface PersonDao extends Dao<Person>,对吗? - Louise

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接