web-dev-qa-db-ja.com

MVCパターンをC#WinFormsアプリケーションに適用するにはどうすればよいですか?

それ以来、MVCパターンを使用してGUIを設計しているC++開発者です。

最近C#に戻りたいと思い、Windowsフォームアプリケーションをセットアップしましたが、MVC準拠の構造にプッシュする方法について少し迷っています。

私が現在やろうとしていることは、WinFormsに与えられたクラスをビューとして「宣言」し、モデルとコントローラーのクラスをバックグラウンドで追加することです。ただし、ボタンのクリックなど、イベントの操作方法についてはよくわかりません。通常、これらのイベントをコントローラーにリダイレクトし、完了したらビューでアクションを実行します。

これはこの星座ではかなり満足できないと感じます。たとえば、「終了」ボタンを実装したい場合は、ビューからコントローラーにイベントをリダイレクトし、ビューに追加のパブリックメソッドを実装する必要があります。最初のインスタンスのビューからClose()を呼び出すだけです。

私に何かアドバイスはありますか? C#でのWindowsフォームに関する私の理解は、MVC実装を試すにはまだ十分ではありませんか?フォームクラスに間違った役割を与えていますか? MVCは単にこのユースケースに不適切なアーキテクチャですか?

11
Sossenbinder

偶然にも、私はMVCを模したWinFormsプロジェクトに取り組んでいます。私はこれを完璧な答えとは言いませんが、私の全体的なデザインを説明します。うまくいけば、これがあなた自身のアイデアを思いつくのに役立つでしょう。

このプロジェクトを始める前に読んだことからすると、これを実装する「正しい」方法はないようです。シンプルなOOPとMVCの設計原則に従いました。ワークフローを開発するにあたり、残りは試行錯誤でした。

MVCは単にこのユースケースに不適切なアーキテクチャですか?

いいえ..?あなたの質問にはそれに対する直接的な答えを提供するのに十分な文脈がありません。そもそもなぜMVCを使用しているのですか?プロジェクトの非機能要件は何ですか?あなたのプロジェクトは非常にUIが重いでしょうか?あなたはセキュリティについてもっと気にしていますか?プロジェクトの主なコンポーネントは何ですか?おそらく、各コンポーネントには異なる設計パターンが必要です。そもそもなぜこのデザインパターンを使用したいのかを見つけてください。自分の質問に答えることができます;)

MVCを使用する理由:私の意見で理解するのはかなりシンプルなデザインパターンであり、私のデザインはユーザーの操作に大きく基づいています。 MVCで開発者が懸念事項を分離できる方法は、私のアプリケーションでも十分です。これにより、コードalotの保守性とテスト性が向上します。

また、ハイブリッドデザインをもっと使用していると思います。通常、ソフトウェアエンジニアリングで提示される理想的な概念は、実際には実際には機能しません。プロジェクトのニーズに合わせて設計を変更できます。何が正しいか間違っているかに巻き込まれる必要はありません。一般的な慣行がありますが、足元で自分を撃たない限り、ルールはいつでも曲がったり壊れたりする可能性があります。

私の実装は、必要なコンポーネントについてのアイデアを与えてくれた高レベルのデザインから始まりました。この方法から始めて、アーキテクチャーを下に向かって進むのが最善です。以下は、StarUMLで作成されたプロジェクトのパッケージ図です。 enter image description here

プレゼンテーション層を除くすべての層がメッセージングシステムに依存していることに注意してください。これは、下位層とそれらの層のサブシステムが相互に通信するために使用する一般的な「言語」です。私の場合、実行可能な操作に基づく単純な列挙でした。これは私を次のポイントに導きます...

操作やコマンドは、実装の基礎と考えてください。アプリケーションで何をしたいですか?それを最も基本的な操作に分解します。例:CreateProject、WriteNotes、SaveProject、LoadProjectなど。GUI(またはフォームクラス)では、(ボタンを押すなどの)イベントが発生します。すべての操作には、コントローラーメソッドが関連付けられています。この場合、Exitのようなものは単純すぎます。アプリケーションは、Formクラスから簡単に閉じることができます。しかし、最初にアプリケーションデータをファイルに永続化したいとしますか?ボタンプレスメソッド内のそれぞれのコントローラークラスから「保存」メソッドを呼び出します。

そこから、コントローラーはServiceクラスから正しい操作セットを呼び出します。アプリケーションのサービスクラスは、ドメインレイヤーへのインターフェイスとして機能します。それらは、コントローラーメソッド呼び出しから(したがってGUIから)受信した入力を検証し、データモデルを操作します。

検証と対応するオブジェクト操作が完了すると、サービスメソッドはメッセージコードをコントローラーに返します。例えば、 MessageCodes.SaveSuccess。コントローラークラスとサービスクラスの両方が、グループ化できるドメインオブジェクトや一般的な操作セットに基づいていました。

例:FileMenuController(操作:NewProject、SaveProject、LoadProject)-> ProjectServices(CreateProject、PersistProjectToFile、LoadProjectFromFile)。ここで、Projectはデータモデルのドメインクラスです。私の場合のコントローラークラスとサービスクラスは、静的メソッドを持つインスタンス化できないクラスでした。

次に、コントローラは、操作が正常に完了したかどうかを認識します。現在、コントローラーには独自のメッセージングシステムがあり、プレゼンテーションレイヤーとのやり取りに使用されているため、サービスレイヤーとプレゼンテーションレイヤーの間に2つの依存関係があります。この場合、ViewStateパッケージのViewModelsというクラスは、コントローラーによって常にGUIに返されます。この状態には、「アプリケーションを有効にしようとした状態ですか?」、「試行した操作に関する人間が読めるメッセージなどの情報が含まれています。実行する理由と、成功したか失敗したか(エラーメッセージ) "とViewModelクラス。

ViewModelクラスには、GUIがビューの更新に使用するドメインレイヤーからの関連データが含まれています。これらのビューモデルはドメインクラスのように見えますが、私の場合、非常にskinnyオブジェクトを使用しました。基本的に、それらにはほとんど動作がなく、アプリケーションの低レベルの状態に関する情報を中継するだけです。つまり、私は[〜#〜] [〜#〜]してドメインクラスをプレゼンテーションレイヤーに提供することはありません。これは、ControllersおよびServicesパッケージがサービスレイヤーを2つの部分に分割する理由でもあります。コントローラはドメインクラスを処理したり、その状態を検証したりすることはありません。それらは、GUI関連データをサービスが使用できるドメイン関連データに、またはその逆に変換する境界として機能します。コントローラーにサービスロジックを含めると、非常にfatコントローラーになり、メンテナンスが難しくなります。

これが出発点になることを願っています。

3
Alluring Topaz