【问题标题】:Persistence contract design: Single generic interface vs. Several specialized interfaces持久性合约设计:单个通用接口与多个专用接口
【发布时间】:2014-02-11 20:39:58
【问题描述】:

我正在开发一个基础库,旨在为大型应用程序提供通用接口,该应用程序旨在支持多个 DBMS(Oracle、SQLServer、MySQL、PostgreSQL 等)。此外,具体的类可以使用 JDBC 或 JPA 与 DBMS 进行交互。

我想提供一个涉及域(模型)类的基本持久性操作的合同,所以我使用泛型制作了这个接口:

public interface IDomainDAO<T> {

    public int insert(T domainObject);

    public int update(T domainObject);

    public int delete(T domainObject);

    public List<T> getList(IQueryFilter queryFilter);
}

注意:IQueryFilter 与我的问题无关。

我正在尝试决定是否应该提供更专业的接口,以便具体类可以实现这些接口而不是IDomainDAO,或者这样做只是浪费时间。例如:

public interface IUserDAO extends IDomainDAO<User>{}

这是一个具体实现的示例:

public class UserDAOJDBC implements IUserDAO {

    public int insert(User domainObject){...};

    public int update(User domainObject){...};

    public int delete(User domainObject){...};

    public List<User> getList(IQueryFilter queryFilter){...};
}

另一方面,实现可以简单地如下所示(而且我不必花一些时间提供专门的接口):

public class UserDAOJDBC implements IDomainDAO<User> {

    public int insert(User domainObject){...};

    public int update(User domainObject){...};

    public int delete(User domainObject){...};

    public List<User> getList(IQueryFilter queryFilter){...};
}

【问题讨论】:

  • 额外的接口有什么用?因为据我所知,如果您需要UserDaoJdbc,您可以将其替换为IDomainDao&lt;? extends User&gt;
  • 另外,我“继承”了一个使用第一种方法的项目。比这个设计问题更重要的是,不要局限于这些方法来实现,添加具体的方法(如UserDao 中的addUserRole)。否则,您的业务逻辑将分散并复制粘贴到各处(最后修复的错误之一需要将相同的代码替换 30 次)。
  • @SJuan76 感谢您的评论,我会记住的。在过去(2 年前),我不得不向完全以这种方式设计的应用程序添加新功能。我必须修改至少 10 个接口/类来添加一个微不足道的功能。我讨厌制作所有这些界面的人,但现在我处于同样的境地,我正努力避免在脚下开枪。

标签: java generics


【解决方案1】:

这归结为设计问题。这取决于您是否认为您会在任何时候向IUserDAO 接口添加不属于IDomainDAO 接口的任何内容。

如果你考虑创建IUserDAO 只是为了让你说implements IUserDAO 作为implements IDomainDAO&lt;User&gt; 的缩写,那么它是没有用的,而且它实际上是额外的接口更冗长。

如果您将IUserDAO 视为IDomainDAO&lt;User&gt; 的特殊形式,则保留接口;这保持了向IUserDAO 添加功能的可能性,这些功能在IDomainDAO&lt;User&gt; 中不存在且不应存在,例如List&lt;User&gt; getActiveUserList() 之类的方法。

【讨论】:

  • 这是我一直在寻找的答案。因为这是我第一次参与此类项目,所以我试图避免在自己的脚下开枪。您的第 3 段给了我保留该界面的充分理由,因为我可能需要在短时间内添加一些功能。谢谢!
【解决方案2】:

我建议避免使用任何 DAO 并改用普通的命令设计模式。如果您使用 JPA,则无需担心 JDBC,因为它支持任何类型的本机查询,并且 JPA 足够智能,可以避免在通过本机查询更新后 JPA 查询中的陈旧对象。
JPA 查询 API 已经是命令设计模式,但您可以定义包装器命令来隐藏 EntityManager API 以方便使用,它还有助于以后升级到更新的 JPA 版本。 命令可以帮助划分事务和重用查询结果处理代码。

如果它不能令人信服并且您决定使用 DAO,那么您可以使用 Spring DAO 包装器,它们可能对事务有用,但命令设计模式有助于避免它。

您可以在此答案DAO implementations 中找到指向 DAO 框架实现的链接

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 2016-03-10
    • 2013-05-03
    • 1970-01-01
    • 2019-10-12
    • 1970-01-01
    相关资源
    最近更新 更多