Сейчас разрабатываю проект на ASP.NET. Для отделения представления данных в слое отображения от логики их формирования и обработки применяю паттерн Model-View-Presenter.
Суть паттерна в том, чтобы ASP.NET форма (View) реализовывала интерфейс, с которым сможет работать представление данных (Presenter), которое в свою очередь оперирует объектами предметной области (Model).
Таким образом, логика приложения отделяется от представления данных. Также, появляется возможность протестировать эту логику.
Теперь от теории к практике. Здесь есть один важный вопрос. Надо ли нам, "пробрасывать" события из Представления в Контроллер?
Первый вариант без "проброса":
1: public partial class CreateNewUser : Page, ICreateNewUserView
2: {
3: protected override void OnInit(EventArgs e)
4: {
5: base.OnInit(e);
6: Submit.Click += Submit_Click;
7: }
8:
9: private void Submit_Click(object sender, EventArgs e)
10: {
11: if (!Page.IsValid)
12: return;
13:
14: Presenter.SubmitCreation();
15: Response.Redirect("RegistrationInformation.aspx");
16: }
17:
18: // остальная часть опущена
19: }
20:
21: public class CreateNewUserPresenter
22: {
23: private void SubmitCreation()
24: {
25: if (string.IsNullOrEmpty(view.Email))
26: return;
27:
28: // логика создания пользователя
29: }
30: }
За первый вариант:
Контроллеру нет разницы после какого события произошел вызов. Если завтра это должно происходить по нажатию на ImageButton или при каком-то другом событии, мы не будем менять Контроллер и интерфейс ICreateNewUserView.
Код Контроллера на много легче тестируется.
Интерфейс Представления содержит только необходимые данные для работы Контроллера. К примеру, Контроллер может запросить поле Email из Представления (и не имеет значения содержится это поле в TextBox или рисуется на экране).
Как следствие - проще сделать mock-объект для интерфейса ICreateNewUserView.
Против первого варианта:
Определённая часть бизнес правил остается в Представлении. К примеру, вызов SubmitCreation только после проверки страницы на валидность.
Второй вариант с "пробросом":
1: public partial class CreateNewUser : Page, ICreateNewUserView
2: {
3: protected override void OnInit(EventArgs e)
4: {
5: base.OnInit(e);
6: Presenter.Init();
7: }
8: }
9:
10: public class CreateNewUserPresenter
11: {
12: public void Init()
13: {
14: view.Submit.Click += Submit_Click;
15: }
16:
17: private void Submit_Click(object sender, EventArgs e)
18: {
19: if (!view.Page.IsValid)
20: return;
21:
22: SubmitCreation();
23: HttpContext.Current.Response.Redirect("RegistrationInformation.aspx");
24: }
25: }
26: // остальная часть опущена
27: }
28:
29: public class CreateNewUserPresenter
30: {
31: private void SubmitCreation()
32: {
33: if (string.IsNullOrEmpty(view.Email))
34: return;
35:
36: // логика создания пользователя
37: }
38: }
За второй вариант:
Возможность протестировать практически всю работу по представлению данных.
Против второго варианта:
Сильная связность Представления и Контроллера. Контроллер должен знать практически все об элементах, из которых построено Представление, и их типах.
Как следствие - "увеличение" интерфейса Представления.
Затруднённое тестирование и создание mock-объектов для Представлений.
Сначала я пробовал второй вариант. Мне очень понравилась идея протестировать буквально все в классе CreateNewUser. Но, к сожалению, поддержка такого варианта работы занимает очень много времени. Поэтому сейчас я остановился на первом варианте. "Пассивное представление" очень удобно в реализации и достаточно хорошо тестируется.
Возможно я упустил какие-то важные моменты и все-таки стоит перейти на второй вариант?
Обсуждение темы на GotDotNet.ru
Ссылки
IoC-контейнер в ASP.NET с использованием шаблона MVP (Model-View-Presenter)
Комментариев нет:
Отправить комментарий