質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.64%

MVP設計の依存性について

解決済

回答 1

投稿

  • 評価
  • クリップ 3
  • VIEW 4,322

memories

score 7

主にUnityでの開発を最近学び始めたのですがMVP設計の依存性についてわからない箇所があるのでご教授お願いしたいと思います。

MVP設計では通常以下の形式になると思います。

Model   ←  Presenter  →  View
            ⇨                  ⇦
→が依存
⇨が変更を通知


この時PresenterがViewとModelを扱う上位レイヤーであるため、依存性逆転の原則からして上位レイヤーのPresenterがViewとModelに依存するのはあまり好ましくないのでしょうか。
またもう少し具体的に考えた時、Viewが増えた際に毎回Controllにも大幅に手を加えなければいけないのは若干好ましくないように感じます。
よって上位レイヤーは抽象に依存させるよう考えると以下の形式になるのではなると思いました。

Model   ➡️  IModel
                  ↑⇩
               Presenter
                  ↓⇧
                 IView ⬅️ View
→が依存
⇨が変更を通知
➡️が継承
(分かりづらくてすみません)


この形であればModelとViewの方がPresenterに依存するようになると思うのですがどうにも自信が持てずにいます。
何か私の理解で間違っている箇所、及びこの形の問題点等あればご教授よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+4

Viewが増えた際に毎回Controllにも大幅に手を加えなければいけないのは若干好ましくない

これを抽象化で解決するのは正しい方法の一つです。
しかしそれは依存性逆転ではなく、汎化による共通化をしているのです。

 MVCについて

MVCやMVPで最も重要なのは、"Modelが他に依存しないこと"です。
その理由は、"変更の多いモジュールが変更の少ないモジュールに依存すべき"だからです。

そしてもう一つ重要な概念として、ModelとViewを分けるフレームワークでは、
"Viewがモデルのデータを取ってくるタイプ"と"ModelのデータをViewに配信するタイプ"、があります。(複合タイプもあります)

上の2つを合わせて考えると以下のようになります。

Viewがモデルのデータを取ってくるタイプ:
Model ← View
変更の多い方が変更の少ない方に依存しているので問題ない

ModelのデータをViewに配信するタイプ:
Model → View
変更の少ない方が変更の多い方に依存してしまっているのでまずい。

そこで間にControllerを入れることでViewの変更がModelに影響しないようにする。
Model ← Controller → View
これも立派な依存性逆転です。

 依存性逆転について

依存性逆転を行う理由は2つあります。
一つは、"変更の少ない箇所が変更の多い箇所に依存しないようにするため"です。
これは、MVCのようにクラス間の依存性で解決できます。
もう一つは、"部品を交換可能にして再利用するため"です。
これには多くの場合インターフェースが用いられます。

部品交換の目的を持たない場合、インターフェースはただの"公開メンバ一覧"になり、
公開メンバを追加編集するたびに、インターフェースとクラスの両方を記述するという意味のない作業を行うことになります。
MVCのそれぞれについて、抽象化すべきかどうか考えてみましょう。

 Model 
"変更の少ない箇所が変更の多い箇所に依存しないようにするため"の視点から見ると、Modelを抽象化する必要はありません。
なぜならModelとControllerの関係は始めから、変更の多い方から変更の少ない方への依存になっているからです。
また、インターフェースは呼び出し側が持つものなので、呼び出し側(Controller側)のIModelの定義に合わせてModelを実装すると、依存性が悪い方向に逆転してしまいます。

"部品を交換可能にして再利用するため"の視点からも、Modelを抽象化する必要はありません。
なぜならModelとはアプリケーションの核となるビジネスロジックなので、これを交換することはありえないからです。
ガワ替えは接続先のデータベースの変更で、
接続方法の変更はModelではなくコンポーネントの交換で、
Viewを他のアプリで使いまわすのはViewの機能分割です。
どれも"Modelの交換"ではありません。

 View 
"変更の少ない箇所が変更の多い箇所に依存しないようにするため"の視点から見ると、Viewを抽象化する意義は微妙です。
なぜならViewはもともと変更の多いモジュールだからです。

"部品を交換可能にして再利用するため"の視点から見ると、Viewを抽象化する価値はありそうです。
異なるプラットフォームに対応する際にまるごと交換することができますし、
2Dのゲームを後々3Dに移植することなどが容易になります。
ただ、開発段階から手入力で抽象化を行うことには少し待ってください。
交換する対象もないのに定義を2重で書くことに意味はありませんし、
インターフェースの抽出は完成後にツールを使って一括で行うことができます。

 Controller 
"変更の少ない箇所が変更の多い箇所に依存しないようにするため"の視点から見ると、Controllerを抽象化する意義も微妙です。
理由はViewと同じく、変更の多いモジュールだからです。

"部品を交換可能にして再利用するため"の視点から見ても、Controllerを抽象化する意義はほとんどなさそうです。
なぜならControllerは誰からも参照されていないので、交換することができないからです。
Viewがコントローラーを参照する場合や、Viewとコントローラーが相互依存するフレームワークなども見かけますが、
Modelに強く依存したControllerを交換することはModelを交換することと同じなので、
やはりControllerを交換することはできなさそうです。

 まとめ

・Modelが他に依存しない限り、残りの依存性は開発するアプリケーションによって柔軟に変えていけばよい
・交換しない部分を抽象化しても、定義を2重に行うことになり意味がない
・交換のための抽象化は、開発完了後にツールで行えばよい

以上です!

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/28 20:01 編集

    ご回答頂き有難うございます。
    私なりに以下のように解釈させて頂きました。
    - 重要なことは変わるものを変わらないものから切り離し,
     変わるものを変わらないものに依存させること
    - インターフェースによる抽象化を行うのはその部品が交換可能な場合に有効
    概念的にはご教授いただきましたので、実際に具体的なクラスをModel、View、Controllerに落とし込んで考えてみようと思います。
    改めて本当に有難うございました。

    キャンセル

  • 2018/01/29 08:15

    一番重要な部分をきちんと理解されているようなのでよかったです!

    開発中に「これってMVC的にどうなの?」と考えることは良いことですが、「MVCってなんだ・・・」のようにどツボにはまりやすくもあります。

    実際に作ってみて、「ここを変更するたにびに毎回あそこも変更するの面倒だな」と感じたら依存性の整理を考えてみる。
    くらいのスタイルで気楽にやるのがよいと思います。

    キャンセル

  • 2018/01/29 20:40

    デザインパターン然りMVC然りですが無理にパターンに当てはめるのではなく、その形が適している場合に有効に用いれば良いということですね。
    初期設計も大切ですが開発中の設計整理も重要だと感じさせて頂きました。
    本当に有難うございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.64%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る