c# - 使用访问者模式从平面 DTO 构建对象图

标签 c# factory-pattern dto visitor-pattern domain-model

我为自己编写了一个非常简单的小域模型,对象图如下所示:

-- Customer
    -- Name : Name
    -- Account : CustomerAccount
    -- HomeAddress : PostalAddress
    -- InvoiceAddress : PostalAddress
    -- HomePhoneNumber : TelephoneNumber
    -- WorkPhoneNumber : TelephoneNumber
    -- MobilePhoneNumber : TelephoneNumber
    -- EmailAddress : EmailAddress

此结构完全与我必须使用的遗留数据库不一致,因此我定义了一个平面 DTO,其中包含客户图中每个元素的数据 - 我有数据库中的 View 和存储过程允许我使用这种平面结构在两个方向上与数据进行交互,这一切都很好&花花公子:)

将领域模型扁平化为 DTO 以进行插入/更新是很简单的,但我遇到的问题是采用 DTO 并从中创建领域模型......我的第一个想法是实现一个访问者客户图中的每个元素,并根据需要从 DTO 注入(inject)值,有点像这样:

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...
}

这就是理论,当它像这样简单地布置时,它似乎是一个合理的想法:)

但要使其正常工作,需要在访问者 erm、访问之前构建整个对象图,否则我会得到 NRE 的左右和中心。

我想要做的是让访问者在访问每个元素时将对象分配给图形,目标是对数据缺失的对象使用特殊情况模式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;
// ...

在这一点上,我意识到我离访客模式很远,而离工厂更近了,我开始怀疑我是否从一开始就错误地处理了这件事。

有没有人遇到过这样的问题?你是如何克服它的?有没有适合这种场景的设计模式?

很抱歉提出这么一个冗长的问题,读到这里做得很好 :)

编辑 为了回应 Florian Greinacher 和 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...
    }
}

最佳答案

我认为你真的把这里的事情复杂化了。只需使用工厂方法,让您的域对象清楚地说明它们所依赖的其他域对象。

class Customer
{
    private readonly Name name;
    private readonly PostalAddress homeAddress;

    public Customer(Name name, PostalAddress homeAddress, ...)
    {
        this.name = name;
        this.homeAddress = homeAddress;
        ...
    }
}

class CustomerFactory
{
    Customer Create(CustomerDTO customerDTO)
    {
        return new Customer(new Name(...), new PostalAdress(...));
    }
}

如果您需要从 Customer 获取对 CustomerDTO 的依赖,将 DTO 作为附加参数传递给构造函数,可能包含在附加抽象中。

这样事情就会保持干净、可测试且易于理解。

关于c# - 使用访问者模式从平面 DTO 构建对象图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6216716/

相关文章:

mapping - 什么时候使用绘图框架,什么时候手动绘图?

c# - 过滤 IEnumerable<string> 不需要的字符串

c# - 检查项目是否不在键值对列表中

c# IEnumerable 双重迭代

c# - 工厂模式和对象持久性

java - Struts 替代 Spring MVC 模型

c# - C# 中 KeyUp 事件处理程序的速率限制

java - 在 jar 文件中隐藏类

java - 如何在不破坏 Guice-AOP 方法拦截的情况下在 Guice 注入(inject)中提供参数?

c# - 如何配置 AutoMapper 将所有引用类型集合转换为整数集合?