MVVMを理解する

# 一体化したView/Modelと、MVVMとの比較

### Model、Viewについて

例：
1 + 2 = 3 の計算処理が、`Model`の役割
1 , 2 を入力し、3を表示するのが、`View`の役割

一体化した`View/Model`とは、コードにおいて、`View`の処理と`Model`の処理を明確に切り分けられない状態。

### アプリの規模と保守の難易度
経験上、アプリの規模・コードの量が増加すると、
- `View/Model`が一体化していると、機能追加や保守が難しく（コードが複雑化）なってゆき、破綻しやすくなる。
- `MVVM`は、一体化した`View/Model`と比べると、アプリの規模が小さくても、機能作成と保守が難しい。
しかし、アプリの規模・コードの量が増えても、機能追加や保守の難しさは変わらない。
なぜなら、`View`, `ViewModel`, `Model`をパターン化できる。そのため、全体のコードを理解しやすく構造化できる。また、`View`が増えても、全体を把握できる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/2ad50d4a-1c2a-1e50-3396-1d2b3088c051.png)

	

# Viewの役割とModelの役割が一体化している例

https://github.com/mikihiro-t/MVVMStudies/tree/master

参照：[CalculationViewOnly プロジェクト](https://github.com/mikihiro-t/MVVMStudies/tree/master/CalculationViewOnly)



`View`のコードビハインドで処理する。
`View`のテキストボックス（`Para1TextBox`, `Para2TextBox`）から値を取得し、計算処理を行い、`View`への表示（`ResultTextBox`）を行う。

```csharp
    private void CalculateButton_Click(object sender, RoutedEventArgs e)
    {
        ResultTextBox.Text = (int.Parse(Para1TextBox.Text) + int.Parse(Para2TextBox.Text)).ToString();
    }
```

### 他のClassから呼び出す
参照：[CaluculationView プロジェクト](https://github.com/mikihiro-t/MVVMStudies/tree/master/CaluculationView)

この計算処理を、他のClassから呼び出すにはどうしたら良いでしょうか？

`View`のコードを次のようにします。

```csharp
    private void CalculateButton_Click(object sender, RoutedEventArgs e)
    {
        Calculate();
    }

    public void Calculate()
    {
        ResultTextBox.Text = (int.Parse(Para1TextBox.Text) + int.Parse(Para2TextBox.Text)).ToString();
    }
```

そして、他の`View`から、計算処理を呼び出してみましょう。




	
- `View`をnewする。
- `View`のテキストボックスのテキストに値をセット。
- 計算処理を呼び出す。
- `View`の計算結果のテキストボックスから値を取得。

この例では、`View`上にある`TextBox`を、値のやりとり（`set, get`)に利用しています。

```csharp
    private void Calculate100Button_Click(object sender, RoutedEventArgs e)
    {
        var view1 = new View();
        view1.Show();

        for (int i = 1; i <= 100; i++)
        {
            view1.Para1TextBox.Text = i.ToString();
            view1.Para2TextBox.Text = i.ToString();
            view1.Calculate();
            Result100TextBox.Text += view1.ResultTextBox.Text +"\r\n";
        }
    }
```

この例のように、`View`と`Model`が一体化していると、`Model`部分の機能を他のクラスから呼び出すのが難しくなります。従って、テストも困難になります。

この例は、極端ですが、コードビハインドで機能を作成してゆくと、似たような状況になりえます。
ではどうすると良いでしょうか？　その回答として`MVVM`があります。

# MVVMの要件
- `View`と、`Model`とを分ける。
- 単に分けるだけでなく、`View`と`Model`とをつなぐ`ViewModel`を間に配置する。
- `Model`は、`ViewModel`と`View`にコード上は依存しない。
- `ViewModel`は、`View`にコード上は依存しない。
- `View`, `ViewModel`, `Model`は、それぞれの役割に応じた処理にする。

`MVVM`の要件は、以上だと考えます。
従って、
- `Dependency Injection`（依存性の注入）は`MVVM`と相性が良いですが、`MVVM`とは関係ありません。
- `View`のコードビハインドは、必要なら行えばよく、コードビハインドで処理しても`MVVM`です。もっとも、コードビハインドを行わない開発方針もあります。

# Viewのコードビハインド
`View`の`.xaml.csファイル`のコードが、`View`のコードビハインドです。
`InitializeComponent()` 以外、書かないようにするという開発方針もあります。その方針を否定はしませんが、
私の考えでは、

:::note
`View`の処理なら、コードビハインドで処理してもOKです。`View`の処理を、`XAML`でするか`C#`でするかの違いにすぎません。
:::

コードビハインドを避けようとして、コードが何行も増えるのは、本末転倒だと考えます。


# MVVMのメリット
`MVVM`は、`View/Model`の一体化では達成が難しかったことが可能になります。
例：
- `View`を変更する際、`Model`の変更は最小ですむ。つまり、`View`の変更が容易になる。
- `Model`を変更する際、`View`の変更は最小ですむ。つまり、`Model`の変更が容易になる。
- `Model`のコードは共通のまま、異なるUIのフレームワークそれぞれに対応する`View`を作成できる。例えば、WPF用の`View`、iOS用の`View`。
- `Model`の作成と、`View`の作成との、分業がしやくすなる。
- `Model`のテストをしやすくなる。

# MVVMのデメリット
[MVVM雑感](https://qiita.com/hiro_t/items/0274565e5a24ba06e0c2)（2019年）に書いたことですが、デメリットはあまり改善されていません。
- データがどこに流れているのか追跡しにくく、デバッグしにくい。
- 全体的に、コードの量が増える。例えば、コードビハインドなら１行ですむものが、`MVVM`に合わせようとすると何行にもなる。
- 学習コストが高い。
- `MVVM`を実現するためのフレームワークもツールもまだまだ足りない、不便。
- `MVVM`のサンプルや解説はどれがお手本として適切なのか見極めるのが難しい。
- 人によって`MVVM`の考え方が異なり、それを反映した解説も様々である。そのため、初学者は混乱する。
- 小規模なアプリなら、開発効率は低下する。

デメリットも多く、`MVVM`が最適な開発方法だとは思いません。ただ、他によさそうな開発方法も思いつきません。ですので、`MVVM`を利用しています。

# MVVMとデータバインディング
データバインディングは、`WPF`の特徴であり、それを利用して`MVVM`は構築されています。
しかし、データバインディングの仕組みがなくても`MVVM`は構築できます。

:::note info
つまり、データバインディングは、`MVVM`の必須の要素ではありません。
:::

参照：[NoBinding プロジェクト](https://github.com/mikihiro-t/MVVMStudies/tree/master/NoBinding)

- `Model`, `ViewModel`に`Para1`などのプロパティを配置する。
- `UpdateViewModel`, `UpdateView`で、
`Model`のプロパティ　→　`ViewModel`のプロパティ　→　`View`の`TextBox.Text` へ値をセット
- `SetParametersOnModel`, `SetParametersOnViewModel`で、
`View`の`TextBox.Text`　→　`ViewModel`のプロパティ　→　`Model`のプロパティ へ値をセット

これにより、`MVVM`の要件はクリアします。

`UpdateViewModel`, `UpdateView`は、`.NET`の`PropertyChanged`イベント（※）の機能の代わりです。

※ `PropertyChanged`は、プロパティの変更を行うと、`View`で`Binding`したオブジェクトに反映する。

#### ViewModel

```csharp
  public void UpdateViewModel()
  {
      Para1 = Model.Para1;
      Para2 = Model.Para2;
      Result = Model.Result;
      UpdateView?.Invoke();
  }
```
#### View
```csharp
    public void UpdateView()
    {
        Para1TextBox.Text = vm.Para1.ToString();
        Para2TextBox.Text = vm.Para2.ToString();
        ResultTextBox.Text = vm.Result.ToString();
    }
```

要は、データバインディングが無くても、データを伝える仕組みがあれば良いわけです。
https://qiita.com/karamage/items/8a9c76caff187d3eb838#comment-9e5f856b2ecdb9b90d80

> このように3層に責務を分離した上で`View`と`ViewModel`間をつなぐために
> `WPF`なら`XAML`などでデータバインディング
> `SwiftUI`なら@Stateなどでつなぐ
> `Jetpack compose`なら`State`でつなぐ
> `Flutter`なら状態変化を監視して`setState`などでつなぐ




# 開発者による実装の違い
`WPF`での`MVVM`の実装の仕方は、開発者によって大きく異なります。どの方針を採用するかで、`MVVM`の難易度が異なります。
例：
- `View`のコードビハインドを許容するかどうか。
- `ViewModel`で`View`のコントロールを処理するか。例えば、引数として`View`のTextBoxコントロールを、`ViewModel`のメソッドに渡し、なんらかの処理をする。
- `MessageBox`の表示をどのように処理するか。例：`Model`, `ViewModel`にサービス（依存性の注入）として実装する。

ただし、少なくとも共通している実装の仕方は、コード上では、「`Model`は、`ViewModel`,`View`に依存しない。`ViewModel`は、`View`に依存しない。」ということです。

# その他
- `MVVM`が提唱された理由の1つは、`Windows Forms`でありがちな、`Model`と`View`との一体化のデメリットを解決するためと考えられます。UI層にモデルの処理を配置すると、テストが困難になり、リファクタリングが難しくなります。
*参照：*2 Design Patterns　Model View Presenter
- `MVVM`が提案された時は、`MVVM`を実現するためのフレームワークも少なく、コードの量がかなり増えました。例えば、Commandをフレームワークなしに実装するのは大変です。今は、[`ReactiveProperty`](https://github.com/runceel/ReactiveProperty)などのフレームワークで実現できるので、かなり楽になります。
- 定期的に、`iOS（SwiftUI）`の開発者から`MVVM`不要論が出てきます。`SwiftUI`での`MVVM`は、`WPF`の`MVVM`と違いが大きいのでしょうか？



# MVVM が提案された頃の考え方

*1
[Introduction to Model/View/ViewModel pattern for building WPF apps](https://learn.microsoft.com/en-us/archive/blogs/johngossman/introduction-to-modelviewviewmodel-pattern-for-building-wpf-apps) 2005/10

> The term means "Model of a View", and can be thought of as abstraction of the view, but it also provides a specialization of the Model that the View can use for data-binding.  In this latter role the ViewModel contains data-transformers that convert Model types into View types, and it contains Commands the View can use to interact with the Model. 

##### 意訳
`ViewModel`とは、「ViewのModel」の意味で、`View`を抽象化したものです。また、同時に、`View`がデータバインディングを利用できるようにするため、`ViewModel`はモデルの特殊化を行います。`ViewModel`は、`Model`を`View`で表示できるように、データ変換を行います。また、`View`が`Model`と相互に対話できるコマンドを含みます。

*2
[Design Patterns　Model View Presenter](https://learn.microsoft.com/en-us/archive/msdn-magazine/2006/august/design-patterns-model-view-presenter) 2006/8

> As UI-creation technologies such as ASP.NET and Windows® Forms become more and more powerful, it's common practice to let the UI layer do more than it should. Without a clear separation of responsibilities, the UI layer can often become a catch-all for logic that really belongs in other layers of the application. 

##### 意訳
`Windows Forms`のようにUIテクノロジが強力だと、他のレイヤーに属しないといけないロジックが、UIレイヤーに配置されてしまいがちです。

> Why is it bad to have lots of logic in the UI layer? The code in the UI layer of an application is very difficult to test without either running the application manually or maintaining ugly UI runner scripts that automate the execution of UI components. While this is a big problem in itself, an even bigger problem is the reams of code that are duplicated between common views in an application. It can often be hard to see good candidates for refactoring when the logic to perform a specific business function is copied among different pieces in the UI layer. 

##### 意訳
UIレイヤーにロジックがあると、テストが困難でリファクタリングが難しくなります。

*3
[THE MODEL-VIEW-VIEWMODEL (MVVM) DESIGN PATTERN FOR WPF | Microsoft Learn](https://learn.microsoft.com/en-us/archive/msdn-magazine/2009/february/patterns-wpf-apps-with-the-model-view-viewmodel-design-pattern) 2009/2
[日本語訳](https://learn.microsoft.com/ja-jp/archive/msdn-magazine/2009/february/patterns-wpf-apps-with-the-model-view-viewmodel-design-pattern)

*4
[デザインパターン - Model-View-ViewModel の問題点と解決策 |Microsoft Learn](https://learn.microsoft.com/en-us/archive/msdn-magazine/2010/july/design-patterns-problems-and-solutions-with-model-view-viewmodel)　2010/7
[日本語訳](https://learn.microsoft.com/ja-jp/archive/msdn-magazine/2010/july/design-patterns-problems-and-solutions-with-model-view-viewmodel)

# MVVMの解説
[Wikipedeiaの解説](https://ja.wikipedia.org/wiki/Model_View_ViewModel)が、よくまとまっているように思えます。しかし、専門用語が多く、それぞれの用語をきちんと理解していないと、この解説も理解できません。