本文へスキップ
BecomeCoder

C#デザインパターンコース · 第3章 現代の設計パターン · レッスン22

MVC ― Model・View・Controller

ブラウザで完結

導入

「データ」「見た目」「操作の受付」がひとかたまりになったコードは、修正のたびに全体が壊れます。MVC は、これらを Model(データ・業務)/View(表示)/Controller(入力の受付と橋渡し) の3つに分ける設計です。Webフレームワークの多くが採用しています。

図解

flowchart LR
    U["ユーザー操作"] --> C["Controller<br/>入力を受け取る"]
    C --> M["Model<br/>データ・業務ルール"]
    M --> C
    C --> V["View<br/>結果を表示"]
    style C fill:#e1f5fe
    style M fill:#e8f5e9
    style V fill:#fff3e0

サンプル

MVCはファイルの分け方そのものがパターンです。実際のWebフレームワークも Models/ Views/ Controllers/ とフォルダで分かれています。ここでも3つの役をファイルに分けました。

1. Model(Counter.cs)。データと業務ルール。表示のことを何も知りません。

// Model: データと業務ルール
public class Counter
{
    public int Value { get; private set; }
    public void Add() => Value++;
}

2. View(CounterView.cs)。表示だけ。業務のことを何も知りません。

// View: 表示だけ
public class CounterView
{
    public void Render(int value) => Console.WriteLine($"カウント: {value}");
}

3. Controller(CounterController.cs)。入力を受けてModelを動かし、結果をViewに渡す橋渡し役。

// Controller: 入力を受けて Model を動かし、View に渡す
public class CounterController
{
    private readonly Counter _model = new();
    private readonly CounterView _view = new();

    public void Increment() => _model.Add();
    public void Show() => _view.Render(_model.Value);
}

4. 入り口(Program.cs)。ユーザー操作の代わりにControllerを呼びます。

var controller = new CounterController();
controller.Increment();
controller.Increment();
controller.Show();   // カウント: 2
  • Model:データと業務ルール(表示を知らない)
  • View:表示だけ(業務を知らない)
  • Controller:入力を受け、Modelを動かし、Viewに渡す橋渡し
  • 3つを分けることで、見た目の変更が業務ロジックに波及しない
  • 「表示を直す=CounterView.csだけ開く」と、触るファイルが最初から決まる

やってみよう

Counter に Reset() を足し、Controller に ResetAndShow() を追加してみましょう。View と Model を触らずに新しい操作を足せることを体感できます。

演習

var c = new MessageController();
c.Set("hello");
c.Show();   // [表示] hello

class Message { public string Text { get; set; } = ""; }
class MessageView { public void Render(string t) => Console.WriteLine($"[表示] {t}"); }

// TODO: Model と View を持ち、Set(text) で Model に保存し Show() で View に表示する MessageController を定義してください
___
  • 期待される出力: [表示] hello
ヒント1を見る

class MessageController { private readonly Message _m = new(); private readonly MessageView _v = new(); public void Set(string t) => _m.Text = t; public void Show() => _v.Render(_m.Text); }

ヒント2を見る

Controllerは自分でModelとViewを持ち、両者の橋渡しをします

まとめ

  • MVCは関心を Model/View/Controller の3つに分ける
  • 表示の変更が業務ロジックに波及しなくなる
  • Web・デスクトップの多くのフレームワークの土台

次回: 読み取りと書き込みを分ける CQRS です。

MVVM(View・ViewModel・Modelの分離)と、INotifyPropertyChanged・ViewModelBaseによるデータバインディングの実践は、 Entity/Repository/Service/ViewModel/View を通しで組み立てる C# MVVMコース で詳しく扱います。

実際に動かしてみよう

このレッスンのサンプルは、実務と同じように役割ごとの .cs ファイルへ分けてあります。下のエディタは最初からその複数ファイルが入った状態で、上のタブでファイルを切り替えられます。そのまま「▶ 実行」を押せば全ファイルをまとめてコンパイルして動かせるので、クラスを足したりファイルをまたいで書き換えたりしながら進めましょう(演習は本文のコードをコピーして Program.cs のタブに貼り付ければ試せます)。

C# — ブラウザ内で実行

ブラウザ内でC#を動かす環境を読み込みます(初回のみ数秒)。
スクロールして表示された時点でも自動で読み込まれます。

次のレッスンへ →