gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 08:23:32 26 4
gpt4 key购买 nike

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

-- 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/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com