はじめに
昔、何度か話題になっていた「モデルに変更通知を実装するかどうか」の議論について、個人的な見解をまとめます。
結論
僕の基本スタンスは「実装しない」派です。
もう少し具体的に言えば、トランザクションスクリプトパターンで開発する場合、モデルは基本的に状態を保持しないため、変更通知を実装する必要性は低いです。
またドメインモデルパターンの場合でも、ドメインモデルは純粋に保ちたいと考えているため、少なくとも INPC は実装しない方がよいと考えています。
ただし、本当に小規模な開発であれば、コスト次第で採用するかもですね。
トランザクションスクリプトパターンの例
トランザクションスクリプトパターンでアプリケーションを作成する場合、以下のような構成になると思います。
ドメインモデルパターンは正直ベース、ちゃんとした実戦経験がないので具体例は避けますが INPC を実装するのは設計思想とは反する認識です。
MyApp/
│
├── Views/ ← UI
│ ├── MainWindow.xaml
│ └── UserView.xaml
│
├── ViewModels/ ← UI 操作・状態管理
│ ├── MainViewModel.cs
│ ├── UserViewModel.cs
│ └── UserRowViewModel.cs
│
├── Models/ ← 実質 Application 層
│ ├── Entities/ ← EF Core Entity
│ │ └── User.cs
│ │
│ ├── Services/ ← ビジネスロジック
│ │ ├── IUserService.cs
│ │ └── UserService.cs
│ │
│ └── Infrastructure/ ← DB / 外部技術など
│ ├── AppDbContext.cs
│ └── DbConnectionFactory.cs
│
├── Common/
│ ├── RelayCommand.cs
│ └── ObservableObject.cs
│
└── App.xaml
この構成では、モデルは薄くなり状態も保持しないため「モデル自身が変更通知を行う」という考え方がなくなります。
また ListView などで使用する行データについては UserRowViewModel としてビューモデルに含めています(これは正直モデルと解釈しても良いと思います)。
補足 1 : 僕のモデルの捉え方について
MVVM から View と ViewModel を引き剝がして、残った Model に Controller と View を付け足して MVC を作った場合でも Model の変更なしで成立することを重視しています。
つまり UI アーキテクチャが変わってもモデルが影響を受けない構成を理想としていますね。
補足 2 : Flutter の MVVM について
各レイヤーの名称こそ異なりますが、自分の捉え方と似ている(というか全く同じ)に見えました。WPF ではありませんが、参考になると思います。
参考
おわりに
昔と今で結構意見が変わりそうですよね。