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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

2回答

4543閲覧

[WPF] MVVMのModelの実装について

tassi-yuzukko

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

1クリップ

投稿2018/08/10 16:10

現在、 WPF ⁺ Prism ⁺ ReactiveProperty で MVVM を勉強中です。

元々 Livet を使ってでWPFアプリを作ったことはあるのですが、現在の主流?が Prism ⁺ ReactiveProperty ということで、勉強しなおしているところです。

そこで気になった点がありますので、質問させていただきます。

Model は最低2レイヤー構成となるのか?

Prism ⁺ ReactiveProperty で Model 層を実装すると、Model 層側で BindableBase を継承したクラスを用意し、それらにゲッターセッタープロパティを持たせることになると思います。

そこで違和感があったのですが、そもそも BindableBase という関心ごとは MVVM を実現するための機能であり、本来の業務ロジックとは異なります。また、クラスにゲッターセッタープロパティを持たせるとカプセル化を破壊することにつながる恐れがあると考えます。(一般的に、業務ロジックを扱うドメイン層では、ゲッターはまだしもセッターは極力使うべきではないと考えています)

となると、BindableBase を継承したクラスは、対 ViewModel 向けの関心ごとを保持していることになるので、もはや MVVM の本来の目的である「ビューからモデル層を独立させる」ということが達成できていないのではと違和感を覚えました。

それを解決するためには、モデル層を以下の最低2レイヤー構成にするほうがいいのか?と思ってきました。

  • 「対 ViewModel 向けの BindableBase を継承したゲッターセッタープロパティを保持するクラス」を扱うレイヤー(つまりViewModelを向けにドメインオブジェクトを加工するレイヤー)
  • 純粋な業務ロジックや、いわゆるインフラ層(ここはプロジェクトや問題の複雑度により任意数のレイヤーとなる)

んなわけないですよね?

自分で書いていてなんですが、ググってもそんな記事見つからないので、上記の疑問は根本から間違っているのかなと思います。
しかし、Model層で「BindableBase を継承したゲッターセッタープロパティを保持するクラス」を他のドメインロジックと同じレベルで扱うことにかなりの違和感があるのは事実です。

ここら辺、 WPF ⁺ Prism ⁺ ReactiveProperty で開発経験のある諸先輩方はどのように考えていらっしゃるのでしょうか。
私の間違っている部分をご指摘いただけると幸いです。
感覚的な質問になってしまいますが、ご教授いただければ助かります。

宜しくお願い致します。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/08/10 21:55

ゲッターセッタープロパティって何ですか?
Zuishin

2018/08/11 00:17

リンク先に「getter/setter プロパティ」が見あたりません。ゲッターとセッターの両方が公開されているプロパティを意味する造語ですか?
Zuishin

2018/08/11 00:18

もしそうだとすれば、なぜそれがカプセル化の破壊に繋がるのかわかりません。プロパティはカプセル化のために実装するものです。
tassi-yuzukko

2018/08/11 00:30

断定的な言い方はよくないですね・・・。正しくは「カプセル化を破壊する手段を外部に提供してしまう」でしょうか。
tassi-yuzukko

2018/08/11 00:32

重ねて失礼します。おっしゃる通り、「getter/setter プロパティ」は「プロパティ」のことを指しています。
Zuishin

2018/08/11 00:38

クラス内で隠蔽すべきデータは外から扱うべきでないので無視してください。プライベートなプロパティを MVVM で扱う設計が間違っています。
tassi-yuzukko

2018/08/11 00:58

すみません、無視するというのは何を無視するべきでしょうか。プロパティがカプセル化を破壊するという考え方を無視するということか、プロパティが存在するクラスがあってもそのプロパティを無視しして実装をするということか・・・。
Zuishin

2018/08/11 02:54

そのプロパティを使わないということです。使わせないために隠蔽しているので使ってはいけません。逆に使わなければならないプロパティであれば公開しなければなりません。隠蔽の行き過ぎです。
hmmm

2018/08/11 03:07

UI側にバインドさせるようなデータは順不同で編集可能なのだから、絶対にsetterが必要ですよね。そのクラスにビジネスロジックを埋め込むのであれば、順不同で設定されても問題ないように単純なプロパティにする感じではないでしょうか?
hihijiji

2019/07/23 03:21

「んなわけないですよね?」以降が「んなわけない」です Modelが層を持つなんて当たり前です。 趣旨と関係ないModelの構造にまで触れていないだけです。
guest

回答2

0

解決済みのようなのでコメントするか悩みましたが、トゲトゲしいコメントしかついてなかったので一応。

仰るとおりINotifyPropertyChangedについては「主としてUIとのバインディングに利用される」ため、Model層への実装に違和感を覚える気持ちはわかります。

ただし、提供している機能はあくまで「プロパティの変更を通知する」ものです。
これ自体単独ではUIとは無関係の話で、オブザーバーパターン実現のひとつの手段に過ぎません。
そこの理解が違うと「ModelはUIを意識しないはずだからおかしい」と混乱するかもしれません。

System.ComponentModelに定義されているものは、あくまでコンポーネント(再利用可能な部品)を構成するものですので、UIと無関係なものでも使えます。そう考えると違和感はありませんよね。

逆にModelが「必ずINotifyPropertyChangedを実装するべき」という発想は間違いだと思います。
これは「目的を実現するための手段」であり、採用するかどうかはケース・バイ・ケースでしょう。

考えるべきは「Modelとして公開するこのオブジェクトのプロパティ変更は必ず通知されるべきか?」であり、そうでないケースがあった場合にINotifyPropertyChangedが実装されていたら、それはおかしいですよね。

投稿2019/05/17 10:41

gentaro

総合スコア8949

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

もちょっとググってみると、私と同じ疑問を持っている人がmsdnのフォーラムでスレッドを立てていました。

WPF MVVMにおけるModelのViewModel, Viewへの対応について

Model にINotifyPropertyChanged を実装」すること

これが私が違和感を抱いていた部分なのですが、リンク先では色々な考え方が提示されており、参考になりました。

個人的には「Modelはビジネスロジックのみに集中しViewを意識しない」ということが最重要であり、そのために Model 層では INotifyPropertyChanged (つまり BindableBase)を実装すべきではないのかなと思いました。(その実現方法として、Model層をUI層向けとビジネスロジック向けに分離する方法もありだなと思いました)

しかし、利便性を重視して、Model 層では INotifyPropertyChanged を実装する方針もありだと思います。

勝手につらつら書きましたが、既に同様の議論が行われており、そこでは方針によりけりだという結論が出ていますので、それを参考にすることで本質問は終了させていただきます。

ありがとうございました。

投稿2018/08/11 03:52

編集2018/08/11 03:55
tassi-yuzukko

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2018/08/12 12:23

全然違う問題なのでもう一度よく読まれることをお勧めします。
tassi-yuzukko

2018/08/13 03:00

すみませんが、コメントをして頂けるならば、「何が」「どう違うのか」をご指摘いただけますでしょうか。(ただの「間違ってます」だけのコメントですと混乱を生むだけです) なお、私が「同じ問題」だと判断したのは、以下の理由です。 私は、「ビューからモデル層を独立させる」目的を達成する過程において、モデル層がビューのために INotifyPropertyChanged (BindableBase) を実装することに違和感があったので、そのことについて質問を提示しました。 上記のフォーラムでは、質問者は「実際WPFでMVVMを意識して作成される際ModelがどのレベルまでViewを意識したコードとなっているのか、今までの経験などから教えていただけると助かります。」と言っており、本質的には私と同様の懸念が根底にあると思いました。また、そのことの解決方法として、モデル層を複数層にするか、利便性を重視してモデル層で INotifyPropertyChanged (BindableBase) を実装することを許容するかという方法論が論じられています。
Zuishin

2018/08/13 03:05

違うところを言うより似ているところを書く方が早いくらいです。 モデル層が INotifyPropertyChanged を実装するのはビューのためではありませんし、そのこととプロパティの隠蔽の問題には何の関連もありません。
tassi-yuzukko

2018/08/13 03:20

> モデル層が INotifyPropertyChanged を実装するのはビューのためではありません ピュアなモデル層では、INotifyPropertyChanged は関心ごとではないと思っていますが、そうではないのでしょうか。(上記フォーラムでは INotifyPropertyChanged の実装はビューのためということで話が進んでいます)モデル層において、オブジェクトの状態が変化したことを外部に何らかの形で通知する必要があるとき、その方法はコールバックであったり、Observerパターンの実装であったり、いろいろあると思います。その中でも、 INotifyPropertyChanged を選択するということは、ビューを意識してのことだと思っていました。(例えば、既に実装済みのモデルが存在したとして、そのモデルを WPF ⁺ Prism で使用する場合、INotifyPropertyChanged を使用したラッパークラスを用意するか、ビューモデル側で直接そのモデルのメソッド等を INotifyPropertyChanged にラップする必要があるかと思います) > プロパティの隠蔽の問題 これは特に質問の本質ではありません。モデル層がビューを意識することに違和感があるわけで、その過程で INotifyPropertyChanged や公開プロパティを実装することに疑問があったのです。
Zuishin

2018/08/13 03:32

ビューにバインドされるのはモデルではなくビューモデルです。 モデルを直接バインドすることもありますが、それができなくても良いように(つまりモデルが INotifyPropertyChanged を実装しなくても良いように)ビューモデルがあります。 そして質問にはプロパティの変更通知についての記述は何もなく、ゲッターセッタープロパティなるものとセッターを隠蔽したプロパティについて書かれています。 この二つは全く別問題であり、それを混同する限り本質的な理解はできないでしょう。 もう一度書きます。 プロパティの通知とプロパティの隠蔽は全く別の問題です。 これらが同じものにしか見えない人に説明するのは大変困難です。 ですから、もう一度それらについて自分で読み直してください。 私にはあなたに理解できるよう説明するのは無理そうです。
tassi-yuzukko

2018/08/13 04:05

> ビューにバインドされるのはモデルではなくビューモデルです。 https://qiita.com/hiki_neet_p/items/e381c687b0644c0e4978#viewとevent 上記のブログ等、複数の Prism ⁺ ReactiveProperty でWPFを実装するサンプルで、モデル層で INotifyPropertyChanged を実装している例が提示されています。 そこで、私はモデル層で INotifyPropertyChanged を実装することに違和感があったわけですが、Zuishin様は INotifyPropertyChanged はビューモデルで実装するという考え方なのですね。 それも一つの方法であり、個人的にはモデル層で INotifyPropertyChanged を実装するより、そのほうがしっくりきます。 > そして質問にはプロパティの変更通知についての記述は何もなく これは、BindableBase を実装することを指していました。 また、プロパティの通知とプロパティの隠蔽は全く別の問題であることはわかっていますし、そのことを混同するような言い方をしたつもりもありません。
Zuishin

2018/08/13 04:36 編集

INotifyPropertyChanged はバインド専門ではありません。 モデルで実装しても問題ありません。 ビューにバインドするかしないかは別の問題です。 しかし、モデルをビューに直接バインドするのが MVVM の基本であるなら、ビューモデルの役割はなくなりますね。 BindableBase はプロパティの変更を通知できますが、質問にあるゲッターセッタープロパティともカプセル化とも何の関係もありません。 あなたは混同していないつもりでしょうが、それはあなたの判断です。 私には複数の問題を混同しているようにしか見えません。 もう一度カプセル化と INotifyPropertyChanged とデータバインディングと MVVM について読み直してください。 私にはあなたに理解できるよう説明するのは無理そうです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問