2

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

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

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

可测试性真的是这种方法的一个问题吗?即使使用纯 Active Record 方法:是否存在数据库逻辑仅代表整个业务逻辑的一小部分的信息系统,并且在哪里模拟数据库访问会很有趣?

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

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

4

1 回答 1

6

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

[...] 是否存在数据库逻辑仅代表整个业务逻辑的一小部分的信息系统,以及在哪些地方模拟数据库访问会很有趣?

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

但是你怎么知道 mock 是否正确地实现了业务逻辑呢?你可以为你的模拟编写单元测试,或者重用你的数据库的单元测试(你确实有它们,对吗?),但这是我不惜一切代价尝试避免的方法!让我重复一遍:永远不要(必须)为你的 mock 编写单元测试。如果您发现自己处于这种情况,请退后几步并检查您的设计,因为有些地方非常不对劲。

将业务逻辑放入数据库只会在模型和数据库之间产生不必要的耦合,并使您的测试层变得非常复杂。关注点分离是这里的关键:模型只关注业务逻辑,数据库只关注持久性,没有别的。

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

我知道,您说过这些方法将委托给存储库,因此域模型(希望)不包含实际的持久性逻辑。但是它怎么知道它应该委托给哪个存储库呢?

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

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

public class Foo extends AbstractPersistentObject {
    public void saveTo(IFooRepository repository) {
        repository.save(this);
    }
}

但是像这样的方法意味着调用者已经有一个repository实例,所以他还不如save()直接在repository上调用该方法。域模型上的任何持久性方法都将过时。

也许我过于简单化了你的问题。你想达到什么目的?你只想要entity.save()语法,还是试图解决更大的问题?

于 2011-04-16T14:46:24.797 回答