私は、次のようなオブジェクトグラフを使用して、シンプルで小さなドメインモデルを作成しました。
-- 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...
}
それは理論であり、それが単純にそのようにレイアウトされているとき、それは健全な考えのように思えます:)
しかし、これが機能するためには、訪問者の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;
// ...
この時点で、私はビジターパターンからかなり離れていて、ファクトリーにはるかに近いことを認識しており、最初からこのことに間違ってアプローチしたのではないかと考え始めています。
他の誰かがこのような問題に遭遇しましたか?どのようにしてそれを克服しましたか?このシナリオに適したデザインパターンはありますか?
そのようなお粗末な質問を投稿して申し訳ありません、そしてこれまで読んでくれてよくやった:)
編集FlorianGreinacherと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...
}
}