[英]Domain Driven Design - testability and the “new” keyword
我一直在尝试在我的新项目中遵循域驱动的设计方法。 我一直使用Spring进行依赖注入,这很好地将我的应用程序代码与构造代码分开,然而,使用DDD我似乎总是有一个域对象想要创建另一个域对象,这两个域对象都有状态和行为。
例如,给定媒体文件,我们希望将其编码为不同的格式 - 媒体资产调用转码服务并接收回调:
class MediaAsset implements TranscodingResultListener {
private NetworkLocation permanentStorage;
private Transcoder transcoder;
public void transcodeTo(Format format){
transcoder.transcode(this,format);
}
public void onSuccessfulTranscode(TranscodeResult result){
Rendition rendition = new Rendition(this, result.getPath(), result.getFormat());
rendition.moveTo(permanentStorage);
}
}
这引发了两个问题:
有一个工厂来创建这个类是我考虑过的,但是为了包含导致问题的“new”关键字,需要大量的代码开销。
这里有一种我想念的方法,还是我只是做错了?
我认为在这种情况下注入RenditionFactory是正确的方法。 我知道它需要额外的工作,但你也从你的班级中删除了SRP违规。 在业务逻辑中构建对象通常很诱人,但我的经验是,对象或对象的注入在100次中有99次得到回报。 特别是如果所提到的对象是复杂的,和/或如果它与系统资源交互。
我假设你的单元测试方法是MediaAsset
测试MediaAsset
。 这样做,我认为工厂是常见的解决方案。
另一种方法是测试整个系统(或几乎整个系统)。 让您的测试访问外部接口[1](用户界面,Web服务接口等),并为系统访问的所有外部系统(数据库,文件系统,外部服务等)创建测试双精度。 然后让测试注入这些外部依赖项。
这样做,您可以让测试完全与行为有关。 测试与实现细节分离。 例如,您可以使用依赖注入来实现Rendition
:测试不关心。 此外,您可能会发现MediaAsset
和Rendition
不是正确的概念[2],您可能需要将MediaAsset
拆分为两个,并将其中的一半与Rendition
合并。 同样,您可以在不担心测试的情况下完成此操作。
(免责声明:外层测试并不总是有效。有时你需要测试常见概念,这需要你编写微测试。然后你可能会再次遇到这个问题。)
[1]最佳级别实际上可能是“域界面”,低于用户界面的级别,您可以使用域语言而不是字符串和整数,并且您可以在这里谈论域操作而不是按钮点击和焦点事件。
[2]也许这实际上是你的问题: MediaAsset
和Rendition
是正确的概念吗? 如果你问你的域专家,他知道这些是什么吗? 如果没有,你真的在做DDD吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.