コンポーネントモデル
本節では、本システムで実装するソフトウェアのコンポーネント分割設計と、本システムの構築にあたり利用するコンポーネントを決定します。
本システムに登場するコンポーネントは次のとおりです。どのコンポーネントが、これまで説明したどのレイヤーに該当するのか、あわせて記載しています。
それぞれのコンポーネントの役割を以下に記載します。
コンポーネント | 役割 |
---|---|
SystemManager |
本システム内で横断的に利用される共有リソースを含みます。 具体的には従業員を表す値オブジェクトなどが含まれます。 |
SystemManager.Presentation | Presentation層のViewおよびViewModelを含みます。 |
SystemManager.Services |
WCFサービスのインターフェースを含みます。 インターフェースの引数や戻り値に登場するクラスなどは、SystemManagerコンポーネントに含むため、インターフェースのみが含まれます。 |
SystemManager.WindowsService | ServiceHost層のコンポーネントです。WCFサービスのロジックはSystemManager.Services.Impleコンポーネントで実装されるため、それをWindowsサービスとしてホストするための実装のみを含みます。 |
SystemManager.Services.Imple |
WCFサービスの実装コンポーネントです。 Servicesコンポーネントで定義されたインターフェースの実装クラスを含みます。 |
SystemManager.DatabaseAccess |
データベースに対するCRUDの実装するData Access Object(Dao)と、テーブルやViewと対になる値オブジェクトであるEntityクラスを含みます。 データベースへの問い合わせにはDapper及びDapper.FastCRUDを利用して行います。 |
Prism.Wpf | MVVMパターンのサポートライブラリであるPrismのWPF用実装コンポーネントです。ICommandの実装クラスや画面ナビゲーションの仕組み、Dependency Injection Container(以降DIコンテナ)のサポートなど、多数のベストプラクティスに基づく実装をサポートします。 |
Prism.Autofac | Pris.WPFにおいて、DIコンテナとしてAutofacを利用するための拡張ライブラリです。 |
Autofac | 本システムのWPFサプリケーションで利用するDIコンテナの実装クラスです。 |
ReactiveProperty | リアクティブ プログラミングをMVVMパターン上で、簡便に利用するためのライブラリです。 |
PropertyChanged.Fody | INotifyPropertyChangedインターフェースの実装を静的コード生成するためのライブラリです。 |
MahApps.Metro | WPFアプリケーションでMetroライクなモダンなユーザーインターフェースを手軽に実現するためのライブラリです。フラットなボタンやスイッチなどの基本的なコントロールも提供しています。 |
AutoMapper |
類似しているが異なるクラスにたいして、値をコピーする用途で利用します。 Database Access層では、データベースへ値を設定する際や、逆に値を取得する際、一旦System.DatabaseAccessコンポーネントで定義されているEntityクラスに保持します。 WCFサービスの引数や戻り値では、SystemManagerコンポーネントで定義された値クラスを利用します。 これら非常に類似したプロパティを保持しており、値の詰め替えが頻繁に必要となるため、本コンポーネントを利用して自動的に詰め替えを実行します。 またSystemManagerコンポーネントで定義された値クラスと、ViewModelの詰め替えにも一部利用します。 |
Catsle.Core | WCFサービスでAspect Oriented Programing(AOP)を行うために利用します。トランザクション制御や、認証処理を、サービスのメソッド群に横断的に適用するためにAOPを利用します。 |
SimpleInjector | WCFサービスで利用するDIコンテナの実装です。 |
Dapper | データベース操作を行うためのMicro ORMライブラリです。 |
Dapper.FastCRUD | Dapperのみでは提供されないCRUD操作をサポートする拡張ライブラリです。 |
各レイヤー別にコンポーネントを分割する理由について
各レイヤー間はすべて一方通行の依存関係にあります。
.NET Frameworkにはnamespaceによるアクセススコープは提供されておらず、代わりにアセンブリ別のアクセススコープ(internal)が提供されています。このため、複数のレイヤーのオブジェクトを同一のアセンブリに配置した場合、依存関係が双方向になることを防ぐことができません。
レイヤー間の依存関係が、一方通行となるように開発環境で担保するために、レイヤー別にアセンブリを分割することとしました。
ViewとViewModelを同一アセンブリした理由について
各レイヤーを異なるアセンブリに分割したのであれば、同様にViewとViewModelも分割するべきなのかも知れませんが、今回はSystemManager.Presentationアセンブリに一緒に格納しています。
最大の理由は、Prismの提供するVisual Studioエクステンションの機能を最大限に活用するためです。Viewを生成すると自動的に対となるViewModelを作成し、ViewとViewModelの紐づけが行われます。
このため、ViewとViewModelを別のアセンブリに分割することは妥協しました。
もちろん、その厳密性を優先するためにアセンブリを分割するという方針も、間違っていないと考えています。私自身、開発チームのメンバー構成や規模によっては分割することも多いです。
Prismの選定理由について
本システムではMVVMのサポートフレームワークとして、Prism for WPFを採用しました。Prismを採用した理由はいくつかあります。
- 現在も積極的に開発が継続されていること
- 日本語の情報が比較的充実していること
- 多数のベストプラクティスが含まれており、自然とそれらを適用できること
Prismはフルスペックに近いMVVMサポートフレームワークであり、テスト容易性や保守性を担保するためのガイダンスやベストプラクティスが多数含まれています。その点がPrismを選択した最大の理由です。
私自身、Prismのその方針に共感しており、ささやかではありますがPrismにContributeしています。
ただし逆に言うと、お仕着せ感の強いフレームワークでもあります。みなさんが各自で蓄積したノウハウがあり、そのためのライブラリやフレームワークをお持ちなのであれば、必ずしもPrismを選ぶ必要はないでしょう。
個人的にはMVVMに馴染みが薄いようであれば、まずはPrismを使ってみて、一通り理解した上で取捨選択することをお勧めいたします。