Построение графа объекта из плоского DTO с использованием шаблона посетителя

Я написал себе красивую простую небольшую модель предметной области с графом объектов, который выглядит следующим образом:

-- 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...
    }
}
12
задан Dave Schweisguth 14 February 2016 в 00:02
поделиться