Active Record模式,存储库模式和可测试性(在java中)

Tri*_*tan 2 activerecord design-patterns domain-driven-design ddd-repositories repository-pattern

对于旨在从Active Record模式和Repository模式中获得最佳效果的以下方法,有什么缺点(例如在可测试性方面)?

每个持久对象都公开save()和delete()方法,但没有静态方法来加载自身,或者加载类似对象的列表:从上层加载是通过直接调用存储库来完成的,以避免持久对象中的静态方法.

"save()"和"delete()"方法只是外观,它们被委托给存储库.

可测试性真的是这种方法的关注点吗?即使使用纯Active Record方法:是否存在信息系统,其中数据库逻辑仅代表整个业务逻辑的一小部分,以及模拟数据库访问的有趣之处?

编辑:这种方法需要持久对象从实现"save()"和"delete()"的AbstractPersistentObject继承,并且它阻止了业务继承,但我认为最好避免业务继承,并用组合替换它,所以它可能是一个优势,而不是一个缺点......?

编辑2:也许这篇文章将更好地解释我想要解决的问题:http://moleseyhill.com/blog/2009/07/13/active-record-verses-repository/

Nie*_*est 6

有两件事引起了一些关注.第一个是这个引用(强调我的):

[...]是否存在信息系统,其中数据库逻辑仅代表整个业务逻辑的一小部分,以及模拟数据库访问的有趣之处?

您是否将业务逻辑放在数据库中?如果是这样:不要这样做,这使得模拟数据库变得非常困难.您必须复制(并维护!)从数据库到模拟的所有业务逻辑,否则您的测试将毫无用处.

但是,您如何知道模拟是否正确实现了业务逻辑?您可以为您的模拟编写单元测试,或重用数据库的单元测试(您确实拥有它们,对吗?),但这是我不惜一切代价避免的方法!让我再说一遍:不要(必须)为你的模拟编写单元测试.如果你发现自己处于这种状况,请退后几步并检查你的设计,因为有一些非常错误的东西.

将业务逻辑放在数据库中只会在模型和数据库之间产生不必要的耦合,并使测试层变得非常复杂.关注点分离是关键:模型仅关注业务逻辑,数据库仅关注持久性,而不关注其他问题.

这让我想到了我的下一个问题:为什么你需要save()delete()你的领域模型上的持久性相关的方法?持久性不属于域模型.

我知道,你说这些方法会委托给一个存储库,所以域模型(希望如此)不包含实际的持久性逻辑.但是它如何知道它应该委托给哪个存储库?

如果您在save()方法中调用服务定位器,则无法将实体保存到多个存储库.您还隐藏了调用者对存储库的依赖性,我认为这是一件坏事.

要解决这些问题,您可以将存储库实例传递给save()方法,如下所示:

public class Foo extends AbstractPersistentObject {
    public void saveTo(IFooRepository repository) {
        repository.save(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是这样的方法意味着调用者已经有了一个存储库实例,所以他也可以save()直接在存储库上调用该方法.域模型上的任何持久性方法都将过时.

也许我过分简化了你的问题.你想要实现的目标是什么?你只想要entity.save()语法,还是想解决更大的问题?