Создает ли Presenter в Model-View-Presenter представления?
Как представления создаются в MVP? Всегда ли их создает докладчик (в дополнение к просмотру в случае подпредставлений)? Или это отдельный сторонний компонент или приложение или что-то, что их создает?
Давайте также добавим, что я, вероятно, собираюсь сделать это на Dojo Toolkit/ExtJS (то есть JavaScript).
Итак, у меня есть эти строки кода:
var v = new MyApp.view.User();
var p = new MyApp.presenter.User();
куда точно должны идти обе линии? Ведущий создает экземпляр представления или наоборот? А что создает экземпляр первой инстанции?
5 ответов
Это зависит...
Основная цель MVP состоит в том, чтобы отделить сложную логику принятия решений от кода пользовательского интерфейса таким образом, чтобы их стало легче понимать и поддерживать. Часто другая цель - сделать логику принятия решений в презентаторе тестируемой.
Шаблон MVP был описан Фаулером в 2004 году, и он удалил его в 2006 году, разделив его на Supervising Conroller (SC) и Passive View (PV). В SC вид привязан к модели, но не в PV; в PV вид изменяется только самим докладчиком.
И в SC, и в PV докладчик должен обновить вид и реагировать на изменения, внесенные пользователем в вид, такие как ввод текста или нажатие кнопки. Когда вы разрешаете методы вызова View для Presenter, возникает проблема, которую вы описываете, потому что View требует ссылки на Presenter и наоборот. Если вы сделаете это, вы просто сможете принять решение, кто запустит все это. Варианты:
- Представление создает экземпляр Presenter. Когда представление загружено, оно передает себя докладчику в функции инициализации на докладчике.
- И наоборот: Presenter создает View и передает себя в View в функции инициализации в View.
- Вы вводите третий объект, который создает и View, и Presenter, соединяет их вместе и инициализирует их обоих.
Все опции позволяют вам достичь "целей MVP" разделения интересов и повышения тестируемости логики принятия решений. Я не думаю, что какой-либо из этих методов теоретически является правильным или неправильным - вам просто нужно выбрать тот, который наиболее соответствует технологии, которую вы используете. И лучше всего быть последовательным в своем выборе на протяжении всего приложения.
Это ваши варианты:
var cvp = new ContactViewPresenter(new ContactView());
ContactViewPresenter
конструкторы this.view = viewParam
и устанавливает this.view.presenter = this
, Он хранит код в Presenter, при необходимости может поменять представления и может пройти макет представления для тестирования.
var cv = new ContactView(new ContactViewPresenter());
ContactView
конструкторы this.presenter = cvpParam
, а также this.presenter.view = this
, Некоторая логика в View, но не много. При необходимости может заменить докладчика.
ContactView cv = new ContactView();
ContactViewPresenter cvp = new ContactViewPresenter();
cv.presenter = cvp;
cvp.view = cv;
cv.init();
cvp.init();
Это намного больше кода.
ContactViewPresenter cvp = new ContactViewPresenter();
Конструктор создает наборы this.view = new ContactView()
а также this.view.presenter = this
,
ContactView cv = new ContactView();
Конструкторы this.presenter = new ContactViewPresenter()
а также this.presenter.view = this
Последние два кажутся слишком связанными.
Один из них хорош тем, что код остается в Presenter и, по-видимому, облегчает тестирование.
Два приятен тем, что вам не нужно слишком заботиться о докладчиках и больше беспокоиться о своих представлениях.
Я не думаю, что докладчик должен создавать представление, которое должно быть сделано сущностью (не в ориентированном на данные смысле, я имею в виду общую сущность) вне триады MVP. Например, инфраструктура Inversion of Control (IoC) (если вы еще не слышали об IoC, посмотрите статью Мартина Фаулера) или какой-то модуль приложения, отвечающий за настройку пользователя.
Если вы используете WebForms, то WebForm OnLoad или Init должны быть тем местом, где вы создаете Presenter - тогда ему передается интерфейсная ссылка на View, который реализует WebForm.
Итак, как то так:
Presenter _presenter;
OnLoad(object sender, EventArgs e)
{
_presenter = new Presenter(this);
_presenter.Initialise();
}
И конструктор Presenter определяется так:
public class Presenter
{
public Presenter(IView viewReference)
{
_viewReference = viewReference;
}
}
Возможно, я немного ошибочен в терминологии, но я думаю, что вам нужно определить корень композиции вашего взаимодействия; с чего начинается взаимодействие?
В приведенном мной примере веб-форм веб-форма создается конвейером Http, а событие OnInit или OnLoad - это первая точка в конвейере (в зависимости от того, какой контекст вам нужен), которую вы можете "подключить" к процессу. Таким образом, вы создаете Presenter и даете ему конкретный экземпляр веб-формы в качестве интерфейса просмотра.
Я не знаю Javascript-фреймворков, которые вы обсуждаете, но я предполагаю, что есть шаг инициализации / вызова - в ASP.NET MVC это происходит, когда включается ActionInvoker, это Main в консольном приложении.