MVP – Model View Presenter – паттерн организации PL (presentation layer – уровень представления).

MVP применяется при создании десктопных интерфейсов. Выделяют три комопнента: есть модель – группа классов, которые отдают данные или получают команды, представление – форма обладающая состоянием и некоторым поведением. Презентер создают для отделения бизнес-логики от деталей GUI-фреймворка. В отличие от MVC в MVP представление определяет презентер, а не наоборот.

MVP обычно строится вокруг существующих GUI-фреймворков. На практике существуют две принципиально различные различные реализации паттерна – Supervising Controller и Passive View.
В первом случае логика помещается в обработчики событий button_click, а сами обработчики помещаются в отдельный класс. Для полной изоляции презентера от деталей представления надо писать достаточно много врапперов\адаптеров.
Во втором случае создается пара интерфейсов для общения между представлением и презентером. При совершении какого-либо действия представление напрямую обращается к презентеру, тот выполняет некоторый код и вызывает установку свойств представления. Passive View способствует максимальному перемещению кода в в презентер, что облегчает тестирование.

Создание MVP в WinForms с помощью Unity.

Создаем новое winforms приложение и грохаем оттуда форму.

Для начала определим служебные интерфейсы.

//Маркерный интерфейс представления
public interface IView
{
}

//Интрефейс презентера
public interface IPresenter<T> where T:IView
{
    T View { get; set; }
}

//Базовый класс для презентера
public abstract class BasePresenter<T> :IPresenter<T> where T:IView
{
    public T View { get; set; }
}

Класс “бизнес-логики” будем использовать тот же, что и в предыдущем посте.

public interface ISayHelloService
{
    string SayHello(string name);
}
 
public class SayHelloSerivce : ISayHelloService
{
    public string SayHello(string name)
    {
        return "Привет, " + name;
    }
}

Теперь определим рабочие интерфейсы.

public interface ISayHelloPresenter : IPresenter<ISayHelloView>
{
    void SayHello();
}

public interface ISayHelloView: IView
{
    string GetInputText();
    void SetOutputText(string text);
}
Для перезнтера код будет тривиальный.
public class SayHelloPresenter : BasePresenter<ISayHelloView>, ISayHelloPresenter
{
    ISayHelloService _service;

    public SayHelloPresenter(ISayHelloService service)
    {
        this._service = service;
    }

    public void SayHello()
    {
        this.View.SetOutputText(_service.SayHello(this.View.GetInputText()));
    }
}
Теперь нарисуем простую формочку:

Form1

В коде напишем следеющее:

public partial class Form1 : Form, ISayHelloView
{
    ISayHelloPresenter _presenter;

    public Form1(ISayHelloPresenter presenter)
    {
        InitializeComponent();
        _presenter = presenter;
        //Циклическая зависимость
        _presenter.View = this; 
    }

    public string GetInputText()
    {
        return textBox1.Text;
    }

    public void SetOutputText(string text)
    {
        textBox2.Text = text;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        _presenter.SayHello();
    }
}

Циклическая зависимость в Passive View не позволяет с помощью контейнера пропихнуть все зависимости. Поэтому передача презентеру ссылки на представление делается в коде view.

Теперь чтобы увязать это вместе надо создать и сконфигурировать контейнер. Сделаем это прямо в Program.cs.

static void Main()
{
    var container = new UnityContainer();
    container
        .RegisterType<ISayHelloService, SayHelloSerivce>()
        .RegisterType<ISayHelloPresenter, SayHelloPresenter>()
        .RegisterType<ISayHelloView, Form1>()
        ;
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run((Form)container.Resolve<ISayHelloView>());
}

Вот и все.

Теги : MVP, Unity, .NET, WinForms, IoC-контейнер