2016-09-21 89 views
0

我试图将无处不在的语言应用于我的域对象。如何将DTO转换为域对象

我想将来自客户端的Data Transfer Object转换为域对象。 Aggregate's Constructor只接受所需的字段,并且即使在创建Aggregate(例如CreateAggregatecommand)时,也应该使用aggregate'sAPI来传递其余参数。

DTOAggregate映射代码变得有点凌乱:

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语句,并与被确认合计(不映射工具)不接受,可以invalide它的业务规则的值,并用具有无处不在语言适用?

请不要告诉我,我可以使用AoutoMapper来伎俩。请仔细阅读最后一部分。'

谢谢。

回答

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; 
} 
+0

你的答案是完美的,但你知道'RegistrantType.Person()'返回枚举值0,而'RegistrantType.Company()'在这个特定情况下返回枚举值1。我没有把这个数字加入到汇总中的原因是为了避免泄漏域的内部。如果我在这个特定情况下创建一个工厂,工厂应该再次返回一个数字作为枚举标志。这听起来像是一个隐含的和贫乏的模型给我。任何建议? – Mohsen

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) 

编写自己的映射器并不难,它允许这种规则和验证属性。我认为它会提高可读性