我给自己写了一个简单的小领域模型,对象图如下所示:
-- 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...
}
这就是理论,当它像这样简单地布置时,它似乎是一个合理的想法:)
但是为了使这个工作,整个对象图需要在访问者之前构建,访问,否则我会得到 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...
}
}