Pergunta

usando MVP, qual é a ordem normal da injeção de construção e de dependência.

Normalmente você cria um apresentador para cada vista e passar a vista para o apresentador no construtor. Mas e se você tem:

  1. Um serviço que múltiplas visões precisa ouvir eventos do.
  2. Várias visões todos apontando para o mesmo cache modelo de dados.

pode exibir um fluxo normal de informações de um usuário clique para dados provenientes de volta em um serviço a partir de um servidor de alguém.

Foi útil?

Solução

Aqui está o que eu faço:

Primeiro, eu definir interfaces teses:

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; }
}

Em seguida, esta classe apresentador resumo:

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;
        }
    }
}

A vista é injectado através de uma propriedade, em vez do construtor, para permitir que o carinho bidireccional na incubadora. Observe que um elenco seguro é necessário ...

Então, o meu apresentador concreto é algo como:

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

Onde implementos IMyView IView. Um tipo de vista betão deve existir (e.g. MyView), mas é o contentor que resolve-lo:

  1. I registar tipo MyPresenter como se no recipiente, com um comportamento transiente.
  2. I registar MyView como um IMyView no recipiente com um comportamento transiente.
  3. Eu, então, pede um MyPresenter ao recipiente.
  4. Container instanciar um MyView
  5. É instanciates um MyPresenter
  6. É injetar a vista para o apresentador através da propriedade AbstractPresenter.View.
  7. O código setter completa a associação bi-direcional
  8. O recipiente retorna o casal Apresentador / Ver

Ele permite injetar outras dependências (serviços, repos) em ambos sua visão e seu apresentador. Mas no cenário que você descreveu, eu recomendo que você injetar serviços e caches para o apresentador , em vez da vista.

Outras dicas

No WinForms, eu prefiro uma abordagem simples. Normalmente você está lidando com alguns UserControls em uma superfície de design - fazer essas suas classes vista. .NET cria a hierarquia de controle para você (via InitializeComponent). Se você usar o Passive View padrão, cada vista, em seguida, instancia-lo do apresentador. (Você pode fazer isso diretamente ou por pedir um recipiente COI). Injeção Use construtor para passar uma referência a interface do fim de construtor do apresentador. O apresentador pode então ligar-se até ver eventos. Repita o processo para o modelo: o apresentador instancia um modelo e fios até os seus eventos. (Neste caso, você não precisa da injeção de construtor desde Passive View diz o apresentador mantém uma referência para o modelo, e não vice-versa.)

A única nit eu encontrei com esta abordagem está a gerir adequadamente vidas do modelo e apresentadora. Você quer manter a visão o mais simples possível, para que você provavelmente não quer que manter uma referência para o apresentador. No entanto, isso significa que você tem este objeto apresentador andando com manipuladores de eventos ligados a sua visão. Esta configuração impede a sua visão de ser lixo coletado. Uma solução é ter a sua visão publicar um evento que indica que de fechamento. O apresentador iria receber o evento e retirar os seus modelos e vista assinaturas. Os objetos em seu web são agora devidamente desreferenciado eo coletor de lixo pode ir sobre o seu trabalho.

Você acabar com algo como o seguinte:

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;
   }
}

Você pode dissociar este exemplo um passo adiante, usando COI e pedir o seu recipiente COI para implementações de IModel (na classe Presenter) e IPresenter (na classe 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 é uma estrutura muito boa MVP para formulários do Windows. Você pode facilmente injetar um serviço através de múltiplos pontos de vista com facilidade usando este quadro. Este é um bom artigo com um código fonte de amostra explica como usar a estrutura.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top