@shirakana

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

MVCの設計とメソッドの書き方について

オブジェクト指向およびMVCを学習する過程でオセロを作っています。

以下のようなプログラムがあるとき、ResetGameメソッド内のController.ResetGameData()はViewがControllerを直接操作してしまっている(MVCに反する)ことになるのでしょうか?

これに問題がある場合は良い設計の仕方も教えていただけるとありがたいです。

データの初期化を分離できればよかったのですが、リセットボタンを押したときに実行したい兼ね合いでこのような書き方になってしまうと思っての実装です。

※質問用に一部を抜粋しているので細かい書式は変えています。

class View
{
    private void ResetGame() //ゲームを初期化し再描画
    {
        Controller.ResetGameData();
    
        DrawLabelsText(Controller.Cells);
        DrawPlayerLabel();
        DrawStoneCount();
        DrawCanPutPoint(Controller.SearchCanPutPoint());
    }

    private void ClickResetButton(object sender, EventArgs e)
    {
        if (MessageBox.Show("最初からプレイしますか?", "リセット", MessageBoxButtons.YesNo) == DialogResult.Yes)
        {
            ResetGame();
        }
    }
}

class Controller
{
    public void ResetGameData() //ゲームの設定を初期化
    {
        Cells.InitializeCellsState(); //全てのセルの初期化 CellInfoがModel
    
        CurrentStone = CellStone.Black;
        CurrentPlayer = Player.Player1;
        PassCount = 0;
    }
}
0 likes

6Answer

そもそも何を作っているのですか? C#、MVC というキーワードからは ASP.NET MVC を想像しますが。

1Like

Comments

  1. @shirakana

    Questioner

    初学者すぎて質問の芯が分からないのですが、おそらく答えとしてはASP.NET Framework 上での開発です。
    MVCにもとづいてオセロの開発をしよう、でやっています。

  2. おそらく答えとしてはASP.NET Framework 上での開発です。

    質問のコードを拝見しましたが、ASP.NET MVC のものとは全く違います。クライアントが使うのがブラウザでなければ ASP.NET MVC ではありませんが、どうなんですか?

    前の質問者さんのスレッドに MainForm という言葉がありましたが、それから想像するに作っているのは Windows Forms アプリ? Windows Forms アプリは MVC パターンにはなじまないので、「MVCを学習する」には不適切だと思いますけど。

    WPF アプリには MVC から派生した MVVM パターンを使うためのライブラリがあって、それをベースに実装していくという話になるようですが。

  3. @shirakana

    Questioner

    Formsアプリとしての開発ですね…

    ついさきほど自分も調べている中でMVVMの考え方を知りましたが自分が設計しているものはこちらに近いような気がします。

    MVCの観点においてレビューしてみると今Controller(のつもり)として書いているものがある1つのModelとも言えるよう(コマをひっくり返すメソッドなどを含んでいる)になっているのでこれがVMに見える理由なんでしょうか?

    今の知識量では自分で判断しきれる自信が持てることはありませんが、色々と根本から疑う必要があるのかもしれませんね

  4. 上にも書きましたが、Windows Forms アプリは MVC パターンにはなじまないので、「MVCを学習する」には不適切です。それでもあえて MVC フレームワークも自力で実装してやると言ってますか?

  5. @shirakana

    Questioner

    うーん、MVCモデルを意識してクラスを設計してねとしか言われていないので…恐らくそうだと思うのですが

  6. MVCモデルを意識してクラスを設計してねとしか言われていない

    講師に意図を聞きましょう。ここで聞いてもらちが明かない(想像ベースで見当違いの話になってお互い時間の無駄になる)と思います。

  7. @shirakana

    Questioner

    ですよね…
    ただ現状はまだ自分で考えてと具体的な答えが返ってこないので待ちです…

Controllerを通さないといけない処理なら,見かけ上は最初にControllerから呼ばれるという流れで書かないとだいぶ不自然な流れになる気がします.
ASPならリンク経由でControllerがActionを処理する訳ですし.

どっちみちControllerのResetから呼ばれるであろうView.Resetの中でControllerのResetを呼ぶとかいう変なロジックになりかねません.

リセット時の処理をまとめて書きたいのは分かりますがイベントとフィードバックは区別しないとめんどいことになります.

以下リンクはASPじゃないですが参考までにこちらをお読みください.

同じようなことをデスクトップアプリでやりたいならdelegateがありますので活用してください.

1Like

Comments

  1. MAUIでMVVMやる記事があったので置いときます.よかったらこっちも参考までに.

まずあなたの環境について

プログラミングの講師がいるのであれば講師をガンガン使うべきですし、講師が自分で考えろというのであれば、講師を変えたほうがいいです。
まず、第一に質問しても答えをくれないという学習環境が劣悪です。
学校で数学の質問しに行って自分で考えろなんていう教師いますか。居残りしてでも学ぶべきです。
そして、講師にお金を払っているのであれば自分で考えるだけの時間にお金を払っているわけなのだからお金の無駄でもあります。
自分で考えろなんて素人でも言えますし、質問が沸くというのは講義の内容が不十分だからです。質問するだけで課金のようなものを要求されるのであれば別の環境を探してみる方がよいと思います。

MVCという前提

@Vercleneさんの回答の通りではありますが、@Vercleneさんの回答に返信がないのでどういう状況なのかよくわかりません。

MVCやMVVMというアーキテクチャ構成について

まず、

ResetGameメソッド内のController.ResetGameData()はViewがControllerを直接操作してしまっている(MVCに反する)ことになるのでしょうか?

という質問の意図としてはなんなのでしょうか?単に当てはめることに着目しているだけ。。。?
MVCなどの考え方に当てはめる一つの命題としては単体テストを可能にすることです。
簡単な話Resetがどこにあろうが、単体テスト可能なので関数としてviewにあろうがcontrollerにあろうが、別のところに単体の関数としてあろうがテスト可能なのでどこでもよくはあります。

アーキテクチャ構成を考えるとき、単体テスト可能性と役割を考えるとレイヤーは自然と構築できますので、MVCやMVVMはデータフローの問題でしかなくなります。
普通Modelといえばデータベーステーブルのスキーマを指すフレームワークが多いですが、
テーブルに対する取得処理、保存処理をModelに入れると役割(責任)があいまいになります。
なので、普通はRepositoryクラスを用意しようとなります。
Repositoryクラスは当然Modelに問い合わせを行うので依存関係がありますが、単体で取得処理ができてるか?このデータを保存できるのか?のテストが可能です。

何が言いたいかというとMVCやMVVMは構成要素を決めるものではなくデータフローの話だということです。RepositoryクラスはMVCやMVVMともに採用するのが普通ですが、この名前にRなんて含まれていません。

構成としての妥当な設計

上記の点を踏まえてどのような単体要素が必要なのかを改めて考えてみましょう。
Viewに対してしたいテストはある条件の時にUI要素が表示されているか、Disabled化されているかどうかなどです。
UIのレンダリングが責務ですので、オセロのデータを実際に管理するのは別です。
Viewとして、開始時、プレイ時、終了時というUI要素をそれぞれ用意することも考えられますし、抽象化して一つの画面として定義することも可能です。

オセロを行う上ではボードや石というクラスが必要で、
viewはボードの内部状態によってレンダリングできるべきです。

そうすればボードが正常にデータの部分だけに集中して石をおけるか?の単体テストが行えます。
ボードクラスにはtoViewDataなど、オセロのボード上のViewに表示するメソッドが考えられ、インタフェースとして実装するのもよいでしょう。
ログに書き込むためのメソッドなどがあってもよいでしょう。

MVCの流れ

MVCはcontrollerがすべて指示を出します。viewにこのデータを渡すので表示してください!とかModelにこのデータください!とか、このデータ保存してください!とか。

なので、ボードというクラスはコントローラで管理するなど行い、Viewに伝えて、Viewはこのデータがきたらこう表示するということに専念するのが無難な設計です。
その際、ResetGameDataみたいな動的な状態をViewに伝えるのは不自然なので、
NewGameなどのメソッドを作り、「新規画面を表示するためのプロセス」であると考えましょう。そうすれば新しいボードをviewに返す、だとかviewで開始状態のものを表示するということが可能になります。
進行中を表す、ProcessingGameを作り引数を受け取り適切な処理を追加しviewを描画するということも必要です。

Viewは常に新しいインスタンスをコンストラクタを介して作成してもいいでしょうし、データを部分的に変えるだけのメソッドを公開してもよいです。

MVVMではどうか?

MVVMではControllerがViewに指示を出すのとは対照的に、ViewModelというデータホルダーが存在し、どのViewでもViewModelを使用できます。
Viewが必要なViewModelを使うという流れのためMVCとは逆です。

そもそもとしてMVVMのようなアーキテクチャは前述したようにデータの流れであるため厳な意味で責任がControllerとViewModelでは異なりますが、
ViewModelは単体で存在し、Viewも単体で存在するため結合度が低くなります。

まとめ

これらの構成要素は依存性が少なくテスト可能であることを重点におくと関数型プログラミングの基本的な概念、純粋関数の理解などが必要になってきます。
そのためオブジェクト指向を学んだばかりの初学者にとって無難な設計は非常に困難です。
特にオブジェクト指向は自由度が高く様々な責任を持たせられますので、初学者が妥当な設計をするのはまず不可能でしょう。
今回の要件でいえば、オブジェクト指向のメソッドにはデータを取得するためのqueryと内部状態を変更するためのcommandがあるという点を抑えておくと思考の整理の役に立つかもしれません。

0Like

素人なので MVC がどうのとかいう話(というか言葉)はよく知りませんが……

Winformsなら Button とか TextBox とか Label みたいな Control を Form 上に配置したりとかしてると思いますが,
こいつらって,能動的に「俺は適切なタイミングでアプリケーションの何らかのデータを表示するぜ!」とかいうことはしませんよね.
誰かから「以降はコレを表示するように」と指示されたらそれを表示するだけです.
表示更新は誰かが行う必要があります.

Form もそんな感じに作ってみればいいんじゃないでしょうか?
リセットボタンが押されたら「ユーザ様がゲームをリセットしろとおっしゃっているぞ!」という旨を
どこかに通知するけども,ゲームのリセットに伴う何らかの表示更新処理は能動的にはやらない.
通知した結果として本当にゲーム内容がリセットされたのかどうかも知ったことではない.
ゲーム内容がリセットされたならば「そしたらこれをこんな感じに表示しろや」とか「この情報としてはこれを表示しろや」とか,
きっと誰かが Form に指示してくるだろうから,そしたらそれに従うだけ.
(そもそもそれがリセットに伴う表示更新なのかすら知る必要は無い)

質問文内のコードで言えば,
View.ResetGame() の内容は Controller.ResetGameData(); の一文だけ,っていう感じかな.

0Like

なんとなくですが、以下のようなクラス構成にしたらMVCの関係を整理できるのでは?
Othelloは情報や状態を保持するModelです。
リセットボタンの表示はViewですが、ボタン操作はControllerです。
ControllerからOthelloにリセットしろと指示します。
MVCではModel→Viewに変更を通知しますが、依存はView→Modelと逆転させます。
Mainプログラムでこれらの構成・関係を構築します。
GUIインタフェース(Controller/View)をCUIインタフェースに変更したとしても、Modelのコードは一切変更しなくて済むのが理想です。

※ レイアウトの都合で、ResetController から Othello への関連線が抜けています

0Like

This answer has been deleted for violation of our Terms of Service.

Your answer might help someone💌