私はMVVMパターンを学んでいますが、よく出てくるのはデータ型の重複です。
Person
データ型があるとします。直感的に私はそれがこのように見えることを望みます:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public uint Age { get; set; }
}
ただし、代わりにコードにはPersonViewModel
a PersonModel
クラスがあり、多くの場合、シリアル化に使用されるPersonData
クラスもあります。
PersonViewModel
はViewModelの基本クラスから継承し、セッターはRaisePropertyChanged
呼び出しを持ちます。
public class PersonViewModel: ViewModelBase
{
private string _firstName;
public string FirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
OnPropertyChanged("Person");
}
}
...
}
PersonModel
はOnPropertyChanged
を呼び出さず、ViewModelから継承しません。また、これの理由の1つは、ビューをモデルに直接バインドするのではなく、ViewModelにバインドすることです。
PersonData
は同じプロパティを持ちますが、DataMember
属性でマークされ、クラスはDataContract
属性を持ちます。
2つの質問があります。
1)同じデータ型に対して非常に多くのクラスが本当に必要ですか?それらは通常、まったく同じ特性を持っています。データ型ごとにクラスを1つだけ持つ方が良いのではないですか?
2)問題の1つは、1つのクラスを変更すると、他のクラスも変更する必要があることです。私は次のようなインターフェースを使用することを考えました:
public interface IPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public uint Age { get; set; }
}
3つのクラスにインターフェースを実装させます。確かにこれらすべてのクラスが必要な場合、それは一貫性の問題の良い解決策ですか?
3)「モデル」と「ビューモデル」の区別は、データ型レベルで本当に必要ですか?コマンドの呼び出しやデータの表示などを1つのコードユニットが担当し、ビジネスロジックを別のコードユニットが担当するのはなぜ良い考えなのかは確かに理解できますが、コードベース全体で使用されているデータ型を処理していますか?
MVVMでのCRUD操作は不必要に冗長に見えますね。しかし、実際の業務が関わると状況は変わります。
別の問題領域を見てみましょう。
public class Invoice
{
public Address BillingAddress { get; set; }
public Address ShippingAddress { get; set; }
public List<InvoiceItem> Items { get; set; }
public double Shipping { get; set; }
public double Tax { get; set; }
}
この例では、Address
、Invoice
およびInvoiceItem
はすべてデータベース内のテーブルであるため、これらを表すには3つのクラスが必要になります。 InvoiceViewModel
で公開されるフィールドは、上記のクラスのフィールドにより似ています。
これらのクラスがすべて必要ですか?そうです。重要なのは、懸念の分離を促進することです。 ViewModelは、ビューに必要なフィールドのみを公開する必要があります。ビューは、データベースがどのように見えるかに関係する必要はありません。それがViewModelとその基礎となるモデルの仕事です。
DRYの原則では、反復可能なコードブロックだけでなく、さまざまな知識の重複を避けるように規定しています。 2つの同一のコードブロックが非常に異なるルールに対応している可能性があり、そのような「複製」があってもまったく問題ありません。この特定のケースでは、ビューで必要なデータと永続化レイヤーで必要なデータは2つの異なる知識であり、それらが類似または同一のコードを持っているのは偶然です。
100%CRUDアプリは、ビューモデルレイヤーをバイパスしてデータエンティティに直接バインドすることでメリットを得ることができますが、そのようなアプリを書いていると思って騙されていると思います。私は100%crudアプリを見たことがありません。その上に常に少なくともいくつかのロジックがあり、通常はCQRSへの投資とモデルの表示に見返りがあります。
データに関しては、DRYに従っていないことを恐れないでください。実際には、データクラスを複製しないアンチパターンです。読み取りモデルは、データベースへの1:1マッピングであってはなりません。またはデータソース。
ユースケースをサポートするようにマッピングする必要があります。だからあなたのデータベースエンティティは
public class Person
{
FirstName
LastName
SocialSecurityNumber
Age,
SomeListOfRelatedData
}
新しい規制のため、18歳未満のすべてのサブスクリプションをキャンセルする必要があるというユースケースがあるとします。彼らは名前と人の年齢のリストを求めています。
そのビューには、この特定のユースケースに必要なデータのみを保持するカスタムモデルを提供する必要があります。これは、より大規模で複雑なシステムにとってより重要になります。