WPF/Silverlightのエンタープライズアプリケーションアーキテクチャ..あなたは何をしていますか?

私はかなりの時間コミュニティの中で何が生きているのか疑問に思っています。 私は大きなビジネス指向のWPF/Silverlightエンタープライズアプリケーションについて話しています。

理論的には、さまざまなモデルがあります。

  • データモデル(通常、dbテーブル、Edmx/NHibarnate/..マップされたエンティティにリンクされています)
  • ビジネスモデル(実際のビジネスロジックを含むクラス)
  • トランスファーモデル(外部世界/クライアントに公開されたクラス(dto))
  • モデルを表示する(実際のビューがバインドされるクラス)

この分離には明白な利点があります。 しかし、それは実生活で機能しますか?それはメンテナンスの悪夢ですか?

あなたは何をしていますか? 実際には、これらすべてのモデルに異なるクラスモデルを使用していますか? 私はこれに多くのバリエーションを見てきました。例えば:

  • データモデル=ビジネスモデル:データモデルはまずPOCOとして実装され、ビジネスロジックを持つビジネスモデルとしても使用されます。
  • ビジネスモデル=移転モデル=ビューモデル:ビジネスモデルはクライアントにそのまま公開されます。 DTOへのマッピングはありません、..ビューはこのビジネスモデルに直接バインドされます。
  • データモデルを公開したSilverlight RIA Services:データモデル=ビジネスモデル=転送モデルそして時にはTransfer Model = View Modelもあります。
  • ..

私は、「それに依存する」答えがここにあることを知っています。 しかし、それは何に依存するのですか? あなたはどちらのアプローチを使っていますか、それをどのように見直しますか?

共有してくれてありがとう、

よろしく、 コーエン

3

4 答え

良い質問。私は本当にenterprisey何もコード化したことがないので、私の経験は限られていますが、私はキックオフします。

現在の(WPF/WCF)プロジェクトでは、データモデル=ビジネスモデル=転送モデル=モデルを使用しています! DBバックエンドは存在しないため、「データモデル」は事実上XMLにシリアライズされたビジネスオブジェクトです。

私はDTOと一緒に遊んでいましたが、極端に面倒なハウスキーピングをすばやく見つけました。私の中にいままで存在していた早すぎるオプティマイザは、不必要なコピーを嫌っていました。これは私に噛み付くために戻ってくるかもしれません(例えば、commsのシリアル化は、永続化のシリアル化とは異なるニーズを持つことがあります)が、今のところそれほど大きな問題ではありません。

私のビジネスオブジェクトとビューオブジェクトの両方で、値の変更に関する通知をプッシュする必要があったため、同じメソッド(INotifyPropertyChanged)を使用してそれらを実装するのが理にかなっていました。これは、私のビジネスオブジェクトがWPFビュー内に直接バインドされるという素晴らしい副作用を持っていますが、MVVMを使用するとViewModelは必要に応じて簡単にラッパーを提供できます。

これまでのところ、私は大きな問題を抱えていませんでした。 4つの「モデル」をすべて分割すると、このプロジェクトの大きさを考えるのは恐ろしいことです。

私は確かに別のオブジェクトを持つことの利点を見ることができますが、実際には問題になるまで私には、無駄な努力と複雑なようです。

私が言ったように、これはかなり小規模で、数十台のPCで動作するように設計されています。真のエンタープライズ開発者からの他の回答を読むことに興味があります。

2
追加された

MVVMをデザインパターンとして使用して以来、私はその使用を大いに支持しています。私は最近、MVVMを使用して大規模な製品のUIコンポーネントを作成したチームの一員で、すべてのデータベース呼び出しなどを処理するサーバーアプリケーションとやり取りしました。正直言って、これは私が取り組んできたプロジェクトの中で最高のものでした。

このプロジェクトは、

  • データモデル(InotifyPropertyChangedをサポートしない基本クラス)、
  • モデルの表示(INPC、関連ビューのすべてのビジネスロジックをサポート)、
  • 表示(XAMLのみ)、
  • モデルを転送する(データベースを呼び出すメソッドのみ)

Transferモデルを1つのクラスに分類しましたが、実際には複数のレイヤーとして構築されていました。

私はまた、追加の機能を追加したり、データの表示方法を変更したりするために、Modelクラスのラッパーである一連のViewModelクラスを用意しました。これらはすべてINPCをサポートしており、私のUIがバインドされたものです。

私は、MVVMのアプローチが非常に有用であることを発見しました。そして、すべての正直なところでは、コードはシンプルに保たれました。それぞれのビューは、そのビューのビジネスロジックを処理する対応するビューモデルを持っていました。

私は、このようなコードを分けておくと、物事を分かりやすくしていると思います。それぞれのView Modelは、ビューに関連するものしか含まれていないために混乱する危険はありません。繰り返しコードを減らしてください。

もちろん、このコードの利点は、データベースへの呼び出しが、アプリケーションへの呼び出しによってデータベースへの呼び出しが処理されたために、コードが即座にメンテナンス可能になるということです。これは、サービスメソッドの動作が変更される可能性がある返され、必要なパラメータは、UIがこれについて知る必要はありません。同じことがUIのためにあり、コードビハインドのないUIを持つことは、UIを非常に簡単に調整できることを意味します。

欠点は、実際にMVVMに固執し、いくつかの複雑な解決策を理解したくない場合を除き、何らかの理由でコードの背後にあるコードで悲しいことですが、実際のMVVMの実装に固執するのは難しい場合もあります私たちはこれをコードの背後にあるとは考えていませんでした)。

結論として、継承を適切に使用し、設計パターンに固執し、コーディング標準を適用すると、このアプローチは非常にうまくいくと思いますが、逸脱し始めると物事が乱雑になり始めます。

0
追加された

私たちはPurplegoldfishがいくつかの層を追加して投稿したのと同様のアプローチを使用します。私たちのアプリケーションは主にWebサービスと通信し、データオブジェクトは特定のデータベースに束縛されません。つまり、データベーススキーマの変更が必ずしもUIに影響を与える必要はありません。

我々は、以下のサブレイヤからなるユーザインタフェース層を有する。

  1. データモデル:これには、変更通知をサポートするプレーンデータオブジェクトが含まれます。これらはUI上でのみ使用されるデータモデルなので、UIのニーズに合わせてこれらを設計する柔軟性があります。あるいは、これらのオブジェクトのいくつかは、それらの状態を操作するロジックを含んでいるため、明白ではありません。また、多くのデータグリッドを使用するため、各データモデルは、グリッドにバインドできるプロパティのリストを提供する責任があります。

  2. Views:ビューのXAML定義。いくつかの複雑な要件に対応するため、XAMLのみのアプローチに固執しているため、コードの背後にある特定のケースに頼らざるをえませんでした。

  3. ViewModels:ビューのビジネスロジックを定義します。これらのユーザーは、後述のデータアクセスレイヤーのエンティティによって実装されるインターフェイスにもアクセスできます。

  4. モジュールプレゼンター:これは通常、モジュールの初期化を担当するクラスです。このタスクには、このモジュールに関連付けられているビューやその他のエンティティの登録も含まれます。

次に、次を含むデータアクセスレイヤーがあります。

  1. 転送オブジェクト:これらは通常、ウェブサービスによって公開されるデータエンティティです。これらのほとんどは自動生成されます。

  2. WCFクライアントプロキシや他のリモートデータソースへのプロキシなどのデータアダプタ:これらのプロキシは、通常、ViewModelに公開された1つ以上のインターフェイスを実装し、リモートデータソースへのすべての呼び出しを非同期で行い、必要に応じてUI相当のデータモデルへの応答。 AutoMapperを翻訳に使用する場合もありますが、このすべてがこのレイヤーでのみ行われます。 私たちのレイヤーのアプローチは少し複雑ですので、アプリケーションです。 Webサービス、直接データベースアクセス、OGC Webサービスなどの他のタイプのデータソースを含むさまざまな種類のデータソースを処理する必要があります。

0
追加された

いくつかのレイヤーはメンテナンスの悪夢につながることはなく、レイヤーが少なくて済みます。メンテナンスが簡単です。私はなぜそれを説明しようとします。

1) Transfer Model shouldn't be the same as Data Model

たとえば、ADO.Netエンティティ・データ・モデルに次のエンティティがあります。

Customer
{
    int Id
    Region Region
    EntitySet Orders
}

そしてあなたはWCFサービスからそれを返すので、次のようなコードを書いてください:

dc.Customers.Include("Region").Include("Orders").FirstOrDefault();

また、 Region Orders プロパティがnullでも空でもないというサービスの利用者にはどのような問題がありますか?また、 Order エンティティに OrderDetail エンティティのコレクションがある場合、そのエンティティもシリアル化されますか?また、遅延ロードをオフにすることを忘れることがあり、オブジェクトグラフ全体がシリアル化されることがあります。

その他いくつかの状況:

  • 2つのエンティティを結合して1つのオブジェクトとして返す必要があります。

  • FileContent の列以外の File テーブルのすべての情報など、エンティティの一部だけを返すようにしたいとします。 p>
  • テーブルからいくつかの列を追加または削除したいが、新しいデータを既存のアプリケーションに公開したくはない。

だから私はあなたが自動生成エンティティがWebサービスに適していないと確信していると思います。 そのため、次のような転送モデルを作成する必要があります。

class CustomerModel
{
    public int Id { get; set; }
    public string Country { get; set; }
    public List Orders { get; set; }
}

また、Webサービスの既存のコンシューマに影響を与えることなく、データベース内のテーブルを自由に変更できます。また、データベースを変更せずにサービスモデルを変更することもできます。

モデル変換のプロセスを簡単にするために、 AutoMapper ライブラリを使用することができます。

2) It is recommended that View Model shouldn't be the same as Transfer Model

トランスファーモデルオブジェクトをビューに直接バインドすることはできますが、モデルの変更はビューに反映されず、その逆もありません。 ほとんどの場合、ビューモデルクラスは、次のフィーチャをモデルクラスに追加します。

    INotifyPropertyChanged インタフェースを使用したプロパティの変更に関する通知

  • ObservableCollection クラスを使用したコレクションの変更に関する通知

  • プロパティの検証

  • ビューのイベントに対する反応(コマンドまたはデータバインディングとプロパティーセッターの組み合わせを使用)

  • {Binding Converter ...} と同様のプロパティの変換ですが、

また、複数のモデルを結合して単一のビューに表示する必要がある場合もあります。そして、サービスオブジェクトに依存するのではなく、独自のプロパティを定義して、モデルの構造が変更された場合、ビューモデルは同じになるようにする方がよいでしょう。

私は常に上記の3つのレイヤーを使用してアプリケーションを構築しています。それはうまくいきます。だから皆に同じアプローチを使用することをお勧めします。

0
追加された