我正在尝试将无处不在的语言应用于我的域对象。
我想将来自客户端的Data Transfer Object
转换为域对象。 Aggregate's Constructor
仅接受必填字段,其他参数应使用aggregate's
API
传递,即使正在创建Aggregate
时(例如CreateAggregate
command
)。
但是DTO
到Aggregate
映射代码变得有点混乱:
if(DTO.RegistrantType == 0){
registrantType = RegistrantType.Person()
}
elseif(DTO.RegistrantType == 1){
registrantType = RegistrantType.Company()
}
//.....
//.....
var aggregate = new Aggregate(
title,
weight,
registrantType,
route,
callNumber,
)
//look at this one:
if(DTO.connectionType == 0){
aggregate.Route(ConnectionType.InCity(cityId))
}
elseif(DTO.connectionType == 1){
aggregate.Route(ConnectionType.Intercity(DTO.originCityId,DTO.DestinationCityId)
}
//..........
//..........
我应该提到的一件事是这个问题似乎不是特定领域的问题。
如何在不放弃domain internals leakage
的情况下减少这些If-Else语句,并确保聚合(不是映射工具)不接受可以使其无效的值商业规则,并应用无处不在的语言?
请不要告诉我,我可以使用AoutoMapper
来做这个伎俩。请仔细阅读最后一部分。'
谢谢。
答案 0 :(得分:2)
一个典型的答案是将DTO
(实际上是一条消息)转换为Command
,其中该命令将所有参数表示为特定于域的值类型。
void doX(DTO dto) {
Command command = toCommand(dto)
doX(command)
}
void doX(Command command) {
// ...
aggregate.Route(command.connectionType)
}
toCommand
逻辑使用类似Builder
模式的东西来提高代码的可读性是相当常见的。
if(DTO.connectionType == 0){
aggregate.Route(ConnectionType.InCity(cityId))
}
elseif(DTO.connectionType == 1){
aggregate.Route(ConnectionType.Intercity(DTO.originCityId,DTO.DestinationCityId)
}
在像这样的情况下,策略模式可以提供帮助
ConnectionTypeFactory f = getConnectionFactory(DTO.connectionType)
ConnectionType connectionType = f.create(DTO)
一旦你认识到ConnectionTypeFactory是一个东西,你可以考虑构建查找表以选择正确的。
Map<ConnectionType, ConnectionTypeFactory> lookup = /* ... */
ConnectionTypeFactory f = lookup(DTO.connectionType);
if (null == f) {
f = defaultConnectionFactory;
}
答案 1 :(得分:1)
那么为什么不使用更多继承
例如
class CompanyRegistration : Registration {
}
class PersonRegistraiton : Registration {
}
然后您可以使用继承而不是if / else方案的
public class Aggregate {
public Aggregate (CompanyRegistration) {
registantType = RegistrantType.Company();
}
public Aggregate (PersonRegistration p) {
registrantType = RegistrantType.Person();
}
}
你可以应用simmilar逻辑来表示setRoute方法或任何其他大的if / else情况。
另外,我知道你不想听,你可以编写自己的映射器(在aggegate内)映射并验证它的业务逻辑
例如,这个想法来自fluentmapper
var mapper = new FluentMapper.ThatMaps<Aggregate>().From<DTO>()
.ThatSets(x => x.title).When(x => x != null).From(x => x.title)
编写自己的映射器并不难,允许这种规则并验证您的属性。我认为它会提高可读性