質問

MVPを使用して、構築と依存性注入の通常の順序は何ですか。

通常、ビューごとにプレゼンターを作成し、コンストラクターでビューをプレゼンターに渡します。しかし、あなたが持っている場合:

  1. 複数のビューがイベントをリッスンする必要があるサービス。
  2. すべてが同じデータモデルキャッシュを指す複数のビュー。

ユーザーのクリックからサーバーからサービスに戻ってくるデータへの通常の情報の流れを誰かが表示できます。

役に立ちましたか?

解決

これが私がやることです:

最初に、これらのインターフェースを定義します:

public interface IView<TPresenter>
{
    TPresenter Presenter { get; set; }
}

public interface IPresenter<TView, TPresenter>
    where TView : IView<TPresenter>
    where TPresenter : IPresenter<TView, TPresenter>
{
    TView View { get; set; }
}

次に、この抽象プレゼンタークラス:

public abstract class AbstractPresenter<TView, TPresenter> : IPresenter<TView, TPresenter>
    where TView : IView<TPresenter>
    where TPresenter : class, IPresenter<TView, TPresenter>
{
    protected TView view;

    public TView View
    {
        get { return this.view; }
        set
        {
            this.view = value;
            this.view.Presenter = this as TPresenter;
        }
    }
}

ビューは、セッターで双方向の影響を可能にするために、コンストラクターではなくプロパティを介して注入されます。安全なキャストが必要なことに注意してください...

その後、私の具体的なプレゼンターは次のようなものです:

public class MyPresenter : AbstractPresenter<IMyView, MyPresenter>
{
    //...
}

IMyView IView を実装する場所。具象ビュータイプが存在する必要があります(例: MyView )が、それを解決するのはコンテナです:

  1. 一時的な動作で、 MyPresenter タイプをコンテナにそれ自体として登録します。
  2. 一時的な振る舞いでコンテナに MyView IMyView として登録します。
  3. 次に、コンテナに MyPresenter を要求します。
  4. コンテナはMyViewをインスタンス化します
  5. MyPresenter
  6. をインスタンス化します
  7. AbstractPresenter.View プロパティを介してプレゼンターにビューを挿入します。
  8. セッターコードは双方向の関連付けを完了します
  9. コンテナはカップルのプレゼンター/ビューを返します

ビューとプレゼンターの両方に他の依存関係(サービス、リポジトリ)を注入できます。ただし、説明したシナリオでは、サービスとキャッシュをに注入することをお勧めします。ビューの代わりにプレゼンター

他のヒント

WinFormsでは、単純なアプローチを好みます。通常、デザインサーフェイスでいくつかのUserControlを処理しています。これらをビュークラスにします。 .NETは(InitializeComponentを介して)コントロール階層を作成します。 パッシブビューパターンを使用する場合、各ビューはプレゼンターをインスタンス化します。 (これは、直接行うか、IOCコンテナに問い合わせることによって行うことができます。)コンストラクターインジェクションを使用して、ビューのインターフェイスへの参照をプレゼンターのコンストラクターに渡します。その後、プレゼンターは自分自身を接続してイベントを表示できます。モデルのプロセスを繰り返します。プレゼンターはモデルをインスタンス化し、そのイベントに結び付けます。 (この場合、パッシブビューでは、プレゼンターがモデルへの参照を保持しているため、その逆ではないため、コンストラクター注入は不要です。)

このアプローチで見つけた唯一の点は、モデルとプレゼンターのライフタイムを適切に管理することです。ビューをできるだけシンプルに保ちたいので、おそらくプレゼンターへの参照を維持したくないでしょう。ただし、これは、このプレゼンターオブジェクトが、ビューに関連付けられたイベントハンドラーとぶらぶらしていることを意味します。この設定により、ビューがガベージコレクションされなくなります。 1つの解決策は、閉じていることを示すイベントをビューに発行させることです。プレゼンターはイベントを受け取り、そのモデルとビューのサブスクリプションの両方を削除します。 Web内のオブジェクトは適切に逆参照され、ガベージコレクターはその作業に取りかかることができます。

次のようになります:

public interface IView
{
   ...
   event Action SomeEvent;
   event EventHandler Disposed;
   ...
}

// Note that the IView.Disposed event is implemented by the 
// UserControl.Disposed event. 
public class View : UserControl, IView
{
   public event Action SomeEvent;

   public View()
   {
      var presenter = new Presenter(this);
   }
}

public interface IModel
{
   ...
   event Action ModelChanged;
   ...
}

public class Model : IModel
{
   ...
   public event Action ModelChanged;
   ...
}

public class Presenter
{
   private IView MyView;
   private IModel MyModel;

   public Presenter(View view)
   {
      MyView = view;
      MyView.SomeEvent += RespondToSomeEvent;
      MyView.Disposed += ViewDisposed;

      MyModel = new Model();
      MyModel.ModelChanged += RespondToModelChanged;
   }

   // You could take this a step further by implementing IDisposable on the
   // presenter and having View.Dispose() trigger Presenter.Dispose().
   private void ViewDisposed(object sender, EventArgs e)
   {
      MyView.SomeEvent -= RespondToSomeEvent;
      MyView.Disposed -= ViewDisposed;
      MyView = null;

      MyModel.Modelchanged -= RespondToModelChanged;
      MyModel = null;
   }
}

IOCを使用し、IOCコンテナにIModel(Presenterクラス)およびIPresenter(Viewクラス)の実装を要求することにより、この例をさらに分離できます。

interface IEmployee
{
    int EmployeeId {get;}
    string FirstName {get;}
    string LastName {get;}
}
interface IEmployeeRepository
{
    void SaveEmployee(IEmployee employee);
    IEmployee GetEmployeeById(int employeeId);
    IEmployee[] Employees { get; }
}
interface IEmployeeView
{
    event Action<IEmployee> OnEmployeeSaved;
}

interface IEmployeeController
{
    IEmployeeView View {get;}
    IEmployeeRepository Repository {get;}
    IEmployee[] Employees {get;}        
}

partial class EmployeeView: UserControl, IEmployeeView
{
    public EmployeeView()
    {
        InitComponent();
    }
}
class EmployeeController:IEmployeeController
{
    private IEmployeeView view;
    private IEmployeeRepository repository;
    public EmployeeController(IEmployeeView view, IEmployeeRepository repository)
    {
        this.repository = repository;
        this.view = view;
        this.view.OnEmployeeSaved+=new Action<IEmployee>(view_OnEmployeeSaved);
    }

    void  view_OnEmployeeSaved(IEmployee employee)
    {
        repository.SaveEmployee(employee);
    }
    public IEmployeeView View 
    {
        get
        { 
            return view;
        }
    }
    public IEmployeeRepository Repository
    {
        get
        {
            return repository;
        }
    }

    public IEmployee[] Employees
    {
        get 
        {
            return repository.Employees;
        }
    }
}

WinformsMVPは、Windowsフォーム用の非常に優れたMVPフレームワークです。このフレームワークを使用すると、複数のビューに簡単にサービスを簡単に注入できます。 これは良い記事ですサンプルソースコードはフレームワークの使用方法を説明しています。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top