我为自己编写了一个非常简单的小域模型,对象图如下所示:
-- 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/