2016-09-21 123 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) 

編寫自己的映射器並不難,它允許這種規則和驗證屬性。我認爲它會提高可讀性