Я написал себе красивую простую небольшую модель предметной области с графом объектов, который выглядит следующим образом:
-- Customer
-- Name : Name
-- Account : CustomerAccount
-- HomeAddress : PostalAddress
-- InvoiceAddress : PostalAddress
-- HomePhoneNumber : TelephoneNumber
-- WorkPhoneNumber : TelephoneNumber
-- MobilePhoneNumber : TelephoneNumber
-- EmailAddress : EmailAddress
Эта структура полностью в разногласиях с устаревшей базой данных, с которой мне приходится работать, поэтому я определил плоский DTO, который содержит данные для каждого элемента в графе клиента - у меня есть представления и хранимые процедуры в базе данных, которые позволяют мне взаимодействовать с данными, используя эта плоская структура в обоих направлениях, все это прекрасно работает и денди :)
Сглаживание модели предметной области в DTO для вставки / обновления - это прямолинейно, но у меня возникают проблемы с взятием DTO и созданием модели предметной области из это ... моей первой мыслью было реализовать посетителя, который будет посещать каждый элемент в графе клиентов и вводить значения из DTO по мере необходимости, что-то вроде этого:
class CustomerVisitor
{
public CustomerVisitor(CustomerDTO data) {...}
private CustomerDTO Data;
public void VisitCustomer(Customer customer)
{
customer.SomeValue = this.Data.SomeValue;
}
public void VisitName(Name name)
{
name.Title = this.Data.NameTitle;
name.FirstName = this.Data.NameFirstName;
name.LastName = this.Data.NameLastName;
}
// ... and so on for HomeAddress, EmailAddress etc...
}
Это теория, и это кажется разумной идеей когда это выложено просто так :)
Но для этого надо k весь граф объектов должен быть построен до того, как посетитель erm посетил, иначе я бы получил NRE слева направо и по центру.
Я хочу иметь возможность позволить посетителю назначить объектов графа, когда он посещает каждый элемент, с целью использовать шаблон Special Case для объектов, где данные отсутствуют в DTO, например
public void VisitMobilePhoneNumber(out TelephoneNumber mobileNumber)
{
if (this.Data.MobileNumberValue != null)
{
mobileNumber = new TelephoneNumber
{
Value = this.Data.MobileNumberValue,
// ...
};
}
else
{
// Assign the missing number special case...
mobileNumber = SpecialCases.MissingTelephoneNumber.Instance;
}
}
Что я искренне думал, что это сработает, но C # выдает мне ошибку при :
myVisitor.VisitHomePhone(out customer.HomePhoneNumber);
Поскольку вы не можете передавать параметры ref / out таким образом: (
Итак, мне осталось посетить независимые элементы и восстановить график, когда это будет сделано:
Customer customer;
TelephoneNumber homePhone;
EmailAddress email;
// ...
myVisitor.VisitCustomer(out customer);
myVisitor.VisitHomePhone(out homePhone);
myVisitor.VisitEmail(out email);
// ...
customer.HomePhoneNumber = homePhone;
customer.EmailAddress = email;
// ...
На данный момент я знаю, что Я довольно далеко от паттерна посетителей и гораздо ближе к фабрике, и я начинаю задаваться вопросом, не правильно ли я подошел к этому с самого начала ...
Кто-нибудь еще сталкивался с подобной проблемой? Как ты это преодолел? Есть ли какие-либо шаблоны проектирования, которые хорошо подходят для этого сценария?
Приносим извинения за такой длинный вопрос, и хорошо, что дочитали до него :)
EDIT В ответ на полезные ответы Флориана Грайнахера и gjvdkamp, я остановился на относительно простой реализации фабрики, которая выглядит следующим образом:
class CustomerFactory
{
private CustomerDTO Data { get; set; }
public CustomerFactory(CustomerDTO data) { ... }
public Customer CreateCustomer()
{
var customer = new Customer();
customer.BeginInit();
customer.SomeFoo = this.Data.SomeFoo;
customer.SomeBar = this.Data.SomeBar
// other properties...
customer.Name = this.CreateName();
customer.Account = this.CreateAccount();
// other components...
customer.EndInit();
return customer;
}
private Name CreateName()
{
var name = new Name();
name.BeginInit();
name.FirstName = this.Data.NameFirstName;
name.LastName = this.Data.NameLastName;
// ...
name.EndInit();
return name;
}
// Methods for all other components...
}
Затем я написал класс ModelMediator для обработки взаимодействия между уровнем данных и моделью предметной области ...
class ModelMediator
{
public Customer SelectCustomer(Int32 key)
{
// Use a table gateway to get a customer DTO..
// Use the CustomerFactory to construct the domain model...
}
public void SaveCustomer(Customer c)
{
// Use a customer visitor to scan for changes in the domain model...
// Use a table gateway to persist the data...
}
}