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())); } }Теперь нарисуем простую формочку:
В коде напишем следеющее:
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>()); }
Вот и все.