Не думаю, что пойду с посетителем.Это было бы уместно, если вы не знаете во время разработки, какие операции вам нужно выполнить над ним позже, поэтому вы открываете класс, чтобы другие могли писать посетителям, которые реализуют эту логику.Или есть так много вещей, которые вы должны сделать с этим, что вы не хотите загромождать свой класс этим.
То, что вы хотите здесь сделать, - это создать экземпляр класса из DTO.Поскольку структура класса и DTO тесно связаны (вы выполняете отображение в БД, я предполагаю, что вы решаете все проблемы отображения на этой стороне и имеете формат DTO, который отображается непосредственно в структуру вашего клиента), вы знаете, чтоВремя разработки, что вам нужно.Там нет необходимости в большой гибкости.(Тем не менее, вы хотите быть надежным, чтобы код мог обрабатывать изменения в DTO, например, новые поля, без исключения).
По сути, вы хотите создать Customer из фрагмента DTO.Какой у вас формат, просто XML или что-то еще?
Я думаю, я бы просто выбрал конструктор, который принимает DTO и возвращает Customer (пример для XML:)
class Customer {
public Customer(XmlNode sourceNode) {
// logic goes here
}
}
Класс Customer может «обернуть» экземплярDTO и «стать одним».Это позволяет вам очень естественно спроецировать экземпляр вашего DTO на экземпляр клиента:
var c = new Customer(xCustomerNode)
Это обрабатывает выбор шаблона высокого уровня.Вы согласны до сих пор?Вот удар по конкретной проблеме, о которой вы упомянули, пытаясь передать свойства 'по ref'. Я действительно вижу, как DRY и KISS могут там расходиться, но я бы постарался не задумываться над этим.Довольно прямолинейное решение может исправить это.
Так что для PostalAddress у него тоже будет свой конструктор, как и у самого Customer:
public PostalAddress(XmlNode sourceNode){
// here it reads the content into a PostalAddress
}
для клиента:
var adr = new PostalAddress(xAddressNode);
Проблема, которую я вижу здесь, заключается в том, куда вы помещаете код, который выясняет, если это InvoiceAddress или HomeAddress?Это не входит в конструктор PostalAddress, потому что позже может быть другое использование для PostalAddress, вы не хотите жестко кодировать его в классе PostalAddress.
Таким образом, эта задача должна быть обработана в классе Customer.Именно здесь он определяет использование почтового адреса.Он должен быть в состоянии определить по возвращаемому адресу, какой это тип адреса.Я полагаю, что самым простым подходом было бы просто добавить свойство на PostalAddress, которое говорит нам:
public class PostalAddress{
public string AdressUsage{get;set;} // this gets set in the constructor
}
, а в DTO просто указать его:
<PostalAddress usage="HomeAddress" city="Amsterdam" street="Dam"/>
Тогда вы можете посмотреть на негов классе Customer и вставьте его в правильное свойство:
var adr = new PostalAddress(xAddressNode);
switch(adr.AddressUsage){
case "HomeAddress": this.HomeAddress = adr; break;
case "PostalAddress": this.PostalAddress = adr; break;
default: throw new Exception("Unknown address usage");
}
Простой атрибут, который сообщает Клиенту, какой тип адреса будет достаточно, я думаю.
Как это звучит до сих пор?Код ниже объединяет все это.
class Customer {
public Customer(XmlNode sourceNode) {
// loop over attributes to get the simple stuff out
foreach (XmlAttribute att in sourceNode.Attributes) {
// assign simpel stuff
}
// loop over child nodes and extract info
foreach (XmlNode childNode in sourceNode.ChildNodes) {
switch (childNode.Name) {
case "PostalAddress": // here we find an address, so handle that
var adr = new PostalAddress(childNode);
switch (adr.AddressUsage) { // now find out what address we just got and assign appropriately
case "HomeAddress": this.HomeAddress = adr; break;
case "InvoiceAddress": this.InvoiceAddress = adr; break;
default: throw new Exception("Unknown address usage");
}
break;
// other stuff like phone numbers can be handeled the same way
default: break;
}
}
}
PostalAddress HomeAddress { get; private set; }
PostalAddress InvoiceAddress { get; private set; }
Name Name { get; private set; }
}
class PostalAddress {
public PostalAddress(XmlNode sourceNode) {
foreach (XmlAttribute att in sourceNode.Attributes) {
switch (att.Name) {
case "AddressUsage": this.AddressUsage = att.Value; break;
// other properties go here...
}
}
}
public string AddressUsage { get; set; }
}
class Name {
public string First { get; set; }
public string Middle { get; set; }
public string Last { get; set; }
}
и фрагмент XML.Вы ничего не сказали о своем формате DTO, будет работать и для других форматов.
<Customer>
<PostalAddress addressUsage="HomeAddress" city="Heresville" street="Janestreet" number="5"/>
<PostalAddress addressUsage="InvoiceAddress" city="Theresville" street="Hankstreet" number="10"/>
</Customer>
С уважением,
Герт-Ян