web-dev-qa-db-ja.com

MVCでは、誰がオブザーバーの処理を担当しますか?

(MVCを大幅に使用する大きなMATLAB GUIを書いているので、私の例はMATLABで書かれています。しかし、この質問は言語に依存しないと思います。間違っている場合は修正してください。)

私はクラスModelを持っています。これは明らかに私のMVCアプリケーションのモデルです。私が以下を持っていると仮定します:

classdef Model < handle
    properties
        objectA
        objectB
        objectC
    end
end

objectAobjectB、およびobjectCはすべて、監視可能なオブジェクトです。

classdef objectA < handle
    events
        ObjectAEvent
    end
    methods
        function raise(this)
            this.notify('ObjectAEvent', someEventData);
        end
     end
end

等.

ViewModelへの変更に応答するようにしたいとします。特に、ViewObjectAEventイベントに応答することを望んでいます。これを行うには2つの方法があります。

  1. ViewObjectAEventイベントを直接サブスクライブさせます。これでViewModelの内部に結合しました。これはデメテルの法則に違反していると思います。これもMVCの概念に本質的に違反していると確信しています。

  2. 次のように、ModelにイベントをViewに「転送」させます。

    classdef Model < handle
        properties
            objectA
            objectB
            objectC
    
            listeners
        end
        events
            eventFromObjectA
            ...
        end
        methods
            function this = Model
                this.listeners(1) = addlistener(this.objectA, 'ObjectAEvent', @(src, eventdata) this.notify('eventFromObjectA', eventdata);
                ...
            end
        end
    end
    

    これでViewModelを直接監視しますが、Modelはイベントと関連データをViewに渡す必要があります。これはMVCの要点の1つだと思いますが、今では各object_Modelの間に直接結合があります。私はModelが彼のobject_sについて知っておくべきだと思いますが、それでもまだ不快に感じます...

どちらのアプローチがより正しいですか?これらのどちらよりもきれいな他の選択肢はありますか?

(回答には、OOP言語の例があります。MATLABに最も慣れています。)

4
Dang Khoa
  1. ViewObjectAEventイベントを直接サブスクライブさせます。ビューをモデルの内部に結合しました。これは、デメテルの法則に違反していると思います。これもMVCの概念に本質的に違反していると確信しています。

MVCはtotalデカップリングについてではありません。不安定な要素への結合を回避することです。デメテルの法則については、違反していると考える理由を示す必要があります。その名前に「法」という言葉が含まれているにも関わらず、それはまた、難しくて速い原則でもありません。ある時点で違反しないことはほぼ不可能です。

ビューはユーザーインターフェイスの一部であるため、ビュークラスはモデルクラスよりもstableになる傾向があります。ユーザーは情報を表示するための新しい方法を望む傾向があります(最初に正しく表示するのは難しい)など。 Microsoft WordのGUIが何回変更されたにもかかわらず、ドキュメントのモデル(段落、単語、文字、フォント、スタイルなどを考える)はあまり変更されていませんか?

MVCでは、モデルクラスがより安定する傾向があるため、ビューをモデルクラスに直接結合できます。 MVCは、この選択を設計上の選択として行います。モデルクラスが変更された場合(それが発生する可能性があります)、モデルに分離されている変更に対してすべての賭けが行われません。おそらく、ビューも変更する必要があります。

モデルクラスはビューと通信する必要がありますが、MVCは直接結合を避けたいと考えています。この問題を回避するには、ビューを「オブザーバー」に偽装します。 Observer APIは、それを実装するビューがそうでなくても、非常に安定しています。私がMVCを理解している限り、ポイント1で説明した方法で結合しても問題ありません。

ObjectAではなく実際のオブジェクトを使用してみましょう、engineTemperatureとしましょう。温度を表示するビューは、それが何を表示しているかを確実に知るでしょう。ビューは値が温度であることを認識しているため、「度C」の単位が追加される場合があります。温度が上限値を超えると、赤色になる場合があります。ビューが表示するモデル要素にビューが直接結合されるのは正常です。

ただし、その逆は異なります。 engineTemperatureは、それがどのように表示されているか、どの色が使用されているか、誰が表示しているかなどを知らないはずです。ビューを変更すると、温度オブジェクトが「壊れる」可能性があります。したがって、MVCとオブザーバーを使用すると、engineTemperature(オブザーバーパターンのサブジェクトとして)は、オブザーバーが存在することのみを認識します。オブザーバーはすべてオブザーバーAPIをサポートしています。

MVCおよびその他のUI設計の詳細については、 http://martinfowler.com/eaaDev/uiArchs.html#ModelViewController を参照してください。

3
Fuhrmanator