Создает ли 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 и наоборот. Если вы сделаете это, вы просто сможете принять решение, кто запустит все это. Варианты:

  1. Представление создает экземпляр Presenter. Когда представление загружено, оно передает себя докладчику в функции инициализации на докладчике.
  2. И наоборот: Presenter создает View и передает себя в View в функции инициализации в View.
  3. Вы вводите третий объект, который создает и 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 в консольном приложении.

Другие вопросы по тегам