7

パターンについては比較的新しいので、すぐに WinForms のコンテキストで例を示しましょう。

私は基本的な MVP パッシブ ビュー構造を持っています。

public partial class UserView : Form, IUserView
{
    public event EventHandler Save;

    public UserView()
    {
        InitializeComponent();

        new UserPresenter(new UserModel(), this);
    }
}

public class UserPresenter
{
    public UserPresenter(IUser model, IUserView view)
    {
        view.Save += (sender, e) => model.Save();
    }
}

また

public partial class UserView : Form, IUserView
{
    public event EventHandler Save;

    public UserView()
    {
        InitializeComponent();

        new UserPresenter(this);
    }
}

public class UserPresenter
{
    public UserPresenter(IUserView view)
    {
        var model = new UserModel();
        //assuming I have the logic to bind property values from View to Model
        view.Save += (sender, e) => model.Save();
    }
}

私の質問は次のとおりです。

User1) model 、 View 、または Presenterの具体的なインスタンスを誰が知っている必要がありますか?

2) その場合、どのようなメリットがありますか?

3) 私のモデルがビューに依存していないとします。その場合、View が Model を知っていると何が悪いのでしょうか? やっぱりUserViewプレゼンさせられUserModelますよね。

4) プレゼンターがモデルとビューのインターフェイスのみと対話する必要がある場合、イベントハンドラーを呼び出すmodel.SaveにはSave、どこから具体的なインスタンスを取得しますModelか?

ここここに2 つの重複する質問がありますが、それらは私のシナリオを正確に扱っているわけではありません..

4

4 に答える 4

17

厳密に言えば、次のルールが必要です。

  1. モデルはビューまたはプレゼンターを認識していません。
  2. ビューはモデルまたはプレゼンターを認識していません。
  3. プレゼンターはモデルとビューの両方を知っていますが、それらのインターフェースを介してのみ知っています。

プレゼンターは、通常、ビューによって発生するイベントを処理することにより、モデルとビューの間のすべての通信を調整します。だからあなたの質問に答えるために:

1)モデルUser、View、またはPresenterの具体的なインスタンスを誰が知っている必要がありますか?

理想的には、どちらでもありません。プレゼンターは、IUserModelインターフェイスを介してUserModelと通信する必要があります。具体的なインスタンスは、プレゼンターに注入されます(たとえば、コンストラクターを介して)。

2)その場合のメリットは何ですか?

主な利点は、自動化された単体テストです。モックモデルまたはビューをテストユニットに個別に挿入できます。

3)モデルがビューに依存しないと仮定します。その場合、Viewがモデルを知っているとしたら何が問題になりますか?結局、UserViewはUserModelを提示するようになりましたね。

本質的に問題はありません。ビューからモデルへの直接通信をサポートするMVPにはさまざまなバリエーションがあり、通常はデータバインディングを利用します。バインディングコードを最初から作成する必要がないことと引き換えに、ある程度のテスト容易性が失われます。

4)PresenterがModelとViewのインターフェースのみと対話する必要がある場合は、model.Save in Save eventhandlerを呼び出します。ここで、Modelの具体的なインスタンスをどこから取得しますか?

以下に示す簡略化された例などの依存性インジェクション。

public class SamplePresenter
{
     public SamplePresenter(ISampleModel model, ISampleView view)
     {
          view.Saved += (sender, e) => model.Save();
     }
}

public interface ISampleModel
{
     void Save();
}

public interface ISampleView
{
     void Show();
     event EventHandler Saved;
}

public class Program
{
     [STAThread]
     static void Main()
     {
          ISampleModel model = new SampleModel();
          ISampleView view = new SampleView();
          SamplePresenter presenter = new SamplePresenter(model, view);
          view.Show();
     }
}
于 2013-01-18T19:12:22.113 に答える
7

ビューがモデルを知っている場合、何が問題になっていますか? 結局、UserView は UserModel 専用に作られているのではないでしょうか。

何もない。Supervising Controllerこれは、MVP パターンのバリアントで受け入れられているプラ​​クティスです。ビューは単純な操作のモデルと直接対話しますが、より複雑な操作はプレゼンターを通じてマーシャリングされます。にいる間Passive View、すべてがプレゼンターを通過します。

さらに、Jeremy Miller のBuild your own CAB シリーズを参照して、 Supervising ControllerPassive Viewという 2 つのアプローチの違いについて理解を深めてください。

于 2013-01-17T19:58:04.747 に答える
3

プレゼンターはモデルについて知っている必要がありますが、ビューはそうではありません。多くのユーザー インターフェイス アプリケーションでは、プレゼンテーション レイヤーを使用することをお勧めします。プレゼンテーション層は単なるアダプターです。これは、ユーザー インターフェイス レイヤーが使いやすいインターフェイスを提供します (つまり、多数のイベント、バインド可能なプロパティなどを提供します) 一方で、基になるデータ レイヤーを覆い隠します。これにより、データ層の再利用が容易になります。

編集

では、ビューがモデルと直接対話できないのはなぜでしょうか? それは確かにできます。問題は、通常、モデルとビューの間にインピーダンスの不一致があることです。つまり、ビューで使用するのが自然なプログラミング インターフェイスは、モデルが公開するのが自然なインターフェイスと一致しません。ビューのニーズに合わせてモデルを適合させると、モデルと使用している特定のタイプのインターフェースとの間に強い結合が作成されることになります。

たとえば、あなたのアプリは今日は GUI アプリかもしれませんが、明日クラウド用のバージョンを作成するように求められたらどうでしょうか? Winforms に役立つイベントとバインド可能なプロパティは、WCF Rest に切り替えようとすると邪魔になります。プレゼンテーション層を使用すると、コードを新しい環境に適応させるのがはるかに簡単になります。

于 2013-01-17T19:38:20.063 に答える
1

プレゼンテーションパターンを紹介するのにそれほど多くない場合は、MVPのプレゼンターファーストバリアントを確認することをお勧めします。

このバリアントでは、質問への回答を提供することで、プレゼンターはモデルとビューの両方を知っていますが、インターフェイスを介してのみ知っています。ビューもモデルもお互いを知りません。プレゼンターは、イベントとメソッドを介してそれぞれを調整します。

http://atomicobject.com/pages/presenter+first

http://spin.atomicobject.com/2008/01/30/presenter-first-get-your-triads-talking/

例:

Class Presenter {
    private IModel model;
    private IView view;

    void Presenter(IModel model, IView view) {
        _model = model;
        _view = view;
    }

    void Initialise() {
        // Attach handler to event view will raise on save
        _view.OnSave += HandleViewSave();
    }

    void HandleViewSave(){
        _model.Save(_view.GetStuffToSave());
    }
}

非常に基本的な例ですが、要点を示しています。プレゼンターは、ビューとモデル間の通信のための単なる導管です。

プレゼンターの作成は、PoorManのDIまたは適切なコンテナーを使用して行うことができます。

Presenter p = new Presenter(new CustomerModel(), new CustomerForm());

AtomicObjectはプレゼンターへの参照を推奨しないため、実際には次のようになります。

new Presenter(existingCustomerModel, existingCustomerForm);

existingCustomerModel.Initialise();

モデルとビューにスコープがあるという事実は、プレゼンターもその参照を介してスコープ内にとどまるということを意味します...賢い。

于 2013-01-17T19:44:30.320 に答える