Model-View-Presenter
Model-View-Presenter | |
---|---|
Model View Presenter | |
Описан в Design Patterns | Нет |
Model-View-Presenter (MVP) — шаблон проектирования, производный от MVC, который используется в основном для построения пользовательского интерфейса.
Элемент Presenter в данном шаблоне берёт на себя функциональность посредника (аналогично контроллеру в MVC) и отвечает за управление событиями пользовательского интерфейса (например, использование мыши) так же, как в других шаблонах обычно отвечает представление.
Описание шаблона
[править | править код]MVP — шаблон проектирования пользовательского интерфейса, который был разработан для облегчения автоматического модульного тестирования и улучшения разделения ответственности в презентационной логике (отделения логики от отображения):
- Модель (англ. Model) предоставляет данные для пользовательского интерфейса.
- Представление (англ. View) реализует отображение данных (Модели) и маршрутизацию пользовательских команд или событий Presenterʼу.
- Presenter управляет Моделью и Представлением. Например извлекает данные из Модели и форматирует их для отображения в Представлении.
Обычно экземпляр Представления создаёт экземпляр Presenterʼа, передавая ему ссылку на себя. При этом Presenter работает с Представлением в абстрактном виде, через его интерфейс. Когда вызывается событие Представления, оно вызывает конкретный метод Presenterʼа, не имеющего ни параметров, ни возвращаемого значения. Presenter получает необходимые для работы метода данные о состоянии пользовательского интерфейса через интерфейс Представления и через него же передаёт в Представление данные из Модели и другие результаты своей работы.
public class MyModel
{
private int _state = 0;
public MyModel(int initState)
{
_state = initState;
}
public int getState()
{
return _state;
}
}
public class MyView : IView
{
private readonly MyPresenter presenter;
public MyView()
{
presenter = new(this);
}
}
public class MyPresenter
{
private readonly IView _view;
private readonly MyModel model = new(123);
public MyPresenter(IView view)
{
_view = view;
}
}
Количество логики, допустимой в Представлении, различается для разных реализаций.
С точки зрения многоуровневой модели приложений в ООП, Presenter может рассматриваться как самостоятельный уровень между уровнем приложения и уровнем пользовательского интерфейса. В структуре Решения Приложения, Согласно принципам ООП и SOLID, каждый слой должен быть отдельной сборкой или даже набором сборок. Пример выше не позволяет построить полностью абстрактную структуру, что нарушает принципы. Например, любое изменение в Model потребует перекомпиляции Презентера, а его компиляция потребует компиляции Представления. Для устранения таких зависимостей, нарушающих принципы абстракции, Презентер должен работать с Моделью и Представлением через их интерфейсы в отдельных сборках, сборки Модели, Презентера и Представления не должны иметь ссылок друг на друга. Создаются слои и внедряются зависимости в сборке Приложения. Например, метод Main(), который является точкой запуска консольного приложения.
namespace AssembleOfInterfaces
{
public interface IModel
{
IList<int> Numbers { get; }
int Sum();
}
public interface IView
{
int ReadA();
int ReadB();
void WriteSum(int sum);
}
}
using AssembleOfInterfaces;
namespace AssembleOfModel
{
public class MyModel : IModel
{
public IList<int> Numbers { get; } = new List<int>();
public int Sum() => Numbers.Sum();
}
}
using AssembleOfInterfaces;
using static System.Console;
namespace AssembleOfView
{
public class MyView : IView
{
public int ReadA()
{
Write("Коэффициент A: ");
return int.Parse(ReadLine() ?? string.Empty);
}
public int ReadB()
{
Write("Коэффициент B: ");
return int.Parse(ReadLine() ?? string.Empty);
}
public void WriteSum(int sum) => WriteLine($"Сумма коэффициентов = {sum}.");
}
}
using AssembleOfInterfaces;
namespace AssembleOfPresenter
{
public class MyPresenter
{
private readonly IView view;
private readonly IModel model;
public MyPresenter(IModel myModel, IView view)
{
this.view = view;
model = myModel;
}
public void Start()
{
model.Numbers.Add(view.ReadA());
model.Numbers.Add(view.ReadB());
view.WriteSum(model.Sum());
}
}
}
using AssembleOfInterfaces;
using AssembleOfModel;
using AssembleOfView;
using AssembleOfPresenter;
namespace AssembleOfApplication
{
public class App
{
public static void Main()
{
MyModel model = new();
MyView view = new();
MyPresenter presenter = new MyPresenter(model, view);
presenter.Start();
}
}
}
Для тех же Модели и Презентера можно создать другое Представление. Например, Форма с двумя полями, двумя кнопками и лейблом для вывода результата. В начальном состоянии поля и кнопки отключены: Enabled=false. Code Behind формы:
using AssembleOfInterfaces;
using System;
using System.Threading;
using System.Windows.Forms;
namespace AssembleOfFormsView
{
public partial class NumbersForm : Form, IView
{
public NumbersForm()
{
InitializeComponent();
labelSum.Text = "0";
}
private readonly AutoResetEvent readAEvent = new AutoResetEvent(false);
private readonly AutoResetEvent readBEvent = new AutoResetEvent(false);
private int a, b;
public int ReadA()
{
Invoke(new Action(() => textBoxA.Enabled = btnA.Enabled = true));
readAEvent.WaitOne();
return a;
}
public int ReadB()
{
Invoke(new Action(() => textBoxB.Enabled = btnB.Enabled = true));
readBEvent.WaitOne();
return b;
}
private void btnA_Click(object sender, EventArgs e)
{
a = int.Parse(textBoxA.Text);
textBoxA.Enabled = btnA.Enabled = false;
readAEvent.Set();
}
private void btnB_Click(object sender, EventArgs e)
{
b = int.Parse(textBoxB.Text);
textBoxB.Enabled = btnB.Enabled = false;
readBEvent.Set();
}
public void WriteSum(int sum)
{
Invoke(new Action(() => labelSum.Text = sum.ToString()));
}
}
}
Точка сборки:
using AssembleOfFormsView;
using AssembleOfModel;
using AssembleOfPresenter;
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace App
{
static class Program
{
/// <summary>
/// Главная точка входа для приложения.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MyModel model = new MyModel();
NumbersForm view = new NumbersForm();
MyPresenter presenter = new MyPresenter(model, view);
view.Shown += async delegate { await Task.Run(presenter.Start); };
Application.Run(view);
}
}
}
История
[править | править код]Эволюция и несколько вариантов шаблона MVP, в том числе отношения MVP с другими шаблонами проектирования (такими как MVC) были подробно проанализированы в статье Мартина Фаулера[1][2] , а также в статье Дерека Грира[3].
См. также
[править | править код]Примечания
[править | править код]- ↑ «GUI Architectures» Мартин Фаулер. Часть 1 . Дата обращения: 30 мая 2012. Архивировано 11 марта 2013 года.
- ↑ «GUI Architectures» Мартин Фаулер. Часть 2 . Дата обращения: 30 мая 2012. Архивировано 11 марта 2013 года.
- ↑ «Interactive Application Architecture Patterns» Derek Greer . Дата обращения: 30 мая 2012. Архивировано 30 мая 2012 года.
Ссылки
[править | править код]int main()
{
printf("Hi");
return 0;
}
| Это заготовка статьи о программировании. Помогите Википедии, дополнив её. |