动物域 - 域层
public class Study {
private final Long id;
private final Long employeeId;
private Long educationLevelId;
//Other attributes and methods
}
ACADMILEVEL域 - 域层public class educationLevel {
private final Long id;
//Other attributes and methods
}
public class AcademicLevel {
private final Long id;
private List<educationLevel> educationLevels;
//Other attributes and methods
}
Study
域中有一个
findStudiesByEmployeeIdUseCase
StudyDTO
。动物域 - 应用程序层
public class StudyDTO {
private Long id;
private Long employeeId;
private Long educationLevelId;
private Long academicLevelId;
//Other attributes
}
StudyDTO
需要
academicLevelId
,这是另一个域类的属性。为了解决这个问题,我创建了共享服务FindAcademicLevelIdsByEducationLevelIdsService
academicLevel
域的应用层中。
共享域 - 应用程序层
public class AcademicAndEducationLevelIdDTO {
private Long academicLevelId;
private Long educationLevelId;
//Getters
}
public interface FindAcademicLevelIdsByEducationLevelIdsService {
List<AcademicAndEducationLevelIdDTO> execute(List<Long> educationLevelIds)
}
问题是实现使用AcademicLevelRepository
(域层的接口),该实现不应根据六边形体系结构原理取决于应用层。所以我不确定要采用哪种方法。
eption1:
<R> List<R> findAcademicLevelIdsBy(List<Long> educationLevelIds, Class<R> clazz)
AcademicLevelRepository
将不取决于应用程序层。eption2:
AcademicAndEducationLevelIdDTO
。我不喜欢此选项,因为根据六边形体系结构原则,DTOS组件属于应用程序层。
如果还有其他选择,请告诉我。 我需要其他选择或帮助采取更好的选择的帮助。因此,首先要检查的一件事是:
findStudiesByEmployeeIdUseCase
“汇总” - 相关对象的簇,我们将其视为数据更改的单位 - 当...我们没有更改数据时,可能没有用。 如果您不需要聚合,则不需要存储库(可以提供对象的内存集合的幻觉的对象)。 您通常希望有某种形式的立面,充当知道如何检索信息的代码部分之间的信息障碍,以及知道该如何处理的代码部分;但是,该立面并不一定是一个汇总,也可能不是您与域代码打包的东西。
说,如果您确实想使用域模型(因为这是在您的上下文中进行的适当权衡),那么通常的答案是在您的域模型中具有一个看起来像:List<SomeDomainValue> execute(List<Long> educationLevelIds)
然后,在您的
application代码中也有一个看起来像
的功能然后这两件事被组成
List<DTO> dtos = (
(List<SomeDomainValue>) domainObjects
).map( ::someDomainValueToDTO )
在此设计中,应用程序代码知道域模型,但不相反。
<R> List<R> findAcademicLevelIdsBy(List<Long> educationLevelIds, Class<R> clazz)
...那真的很接近另一个好的选择;
Class<R>
可能不是您想要的;因为将引入的耦合。 但是您可以通过相同的想法
<R> List<R> findAcademicLevelIdsBy(List<Long> educationLevelIds, Factory<R> someFactory)
在哪里,您的想法是,有一些由域代码定义的thetounterface
,该接口被定义为接受某些域值作为参数并返回通用事物;然后,您将在应用程序代码中的接口iMplement,该接口知道要返回的东西是适当的dto。
interface DomainModelToSomethingGeneric<R> {
<R> R call(DomainValue domainValue);
}
对于此示例,在您的应用程序代码中,您可能有一些看起来像
class DomainModelToDTO implements DomainModelToSomethingGeneric<DTO> {
DTO call(DomainValue domainValue) {
return someDomainValueToDTO(domainValue);
}
}
在一般情况下,您所拥有的是“依赖性反转”的一种形式 - 域模型实现了协议,并定义了从呼叫者执行该协议所需的功能的收集,并且呼叫代码提供了实现所需功能
当然,这些间接措施具有成本和好处,因此您需要评估它们 - 特别是在增加间接层的额外层次,以便将来更难改变吗?
我们不要遵循这些模式,因为它们是一种使一切变得更好的神奇仪式。我们遵循这些模式,因为它们为我们为某些可能的未来做好了很好的准备。
良好的判断来自经验....