Чи повинен у MVP-образі View представити об'єкт Model на основі вмісту інтерфейсу або просто передати цей вміст як параметри презентатору?


9

Я використовую шаблон MVP в додатку для Android, який я розробляю.

У мене в основному 4 елементи:

  1. AddUserView, де можна додати нового користувача:
  2. AddUserPresenter
  3. UserInfo (pojo)
  4. UserInfoManager (логіка бізнесу та менеджер зберігання)

Моє запитання:

Коли я натискаю кнопку "Додати" в AddUserView, він повинен отримати вміст перегляду тексту, створити інстанцію нового UserInfo і передати його в Presenter. Або повинен AddUserView просто отримати вміст textViews та передати їх AddUserPresenter, який фактично буде інстанціювати UserInfo та передавати його UserInfoManager?

Відповіді:


8

Відповідно до опису MVP Мартіна Фаулера ( http://martinfowler.com/eaaDev/uiArchs.html )

Про перегляд частини MVC Фаулер говорить:

Перший елемент Potel полягає в тому, щоб подати трактування як структуру віджетів, віджетів, які відповідають елементам управління формами та елементами управління та видалити будь-яке розділення перегляду / контролера. Вид MVP - це структура цих віджетів. Він не містить поведінки, яка описує, як віджети реагують на взаємодію користувачів .

(Сміливий акцент міна)

Потім ведучий:

Активна реакція на користувач діє в окремому об’єкті презентатора. Основні обробники жестів користувачів все ще існують у віджетах, але ці обробники просто передають контроль ведучому .

Потім ведучий вирішує, як реагувати на подію. Потель обговорює цю взаємодію насамперед з точки зору дій над моделлю, які вона робить за допомогою команд і виділень. Тут слід підкреслити підхід упаковки всіх редагувань до команди в команді - це забезпечує хорошу основу для відміни / повторення поведінки.

(Знову жирний наголос мій)

Отже, відповідно до вказівок Фоулера, ваш погляд не повинен відповідати за будь-яку поведінку у відповідь на подію кнопки; що включає створення екземпляра UserInfo. Відповідальність за рішення щодо створення об'єкта належить методу Presenter, на який пересилається подія інтерфейсу користувача.

Однак можна також стверджувати, що обробник подій кнопки «Перегляд» також не повинен нести відповідальність за передачу вмісту вашого textView, оскільки перегляд повинен просто пересилати подію кнопки у Презентатор і більше нічого.

Для MVP для перегляду прийнято реалізувати інтерфейс, який ведучий може використовувати, щоб збирати дані безпосередньо з подання (при цьому переконуючись, що ведучий все ще є агностичним для самого представлення). Так як UserInfo є простим POJO, це може бути справедливо для виду , щоб виставити геттер для UserInfo якій ведучий може забрати Фрон View через інтерфейс.

// The view would implement IView
public interface IView {

    public UserInfo GetUserInfo();
}

// Presenter
public class AddUserPresenter {

    private IView addUserView;

    public void SetView(IView view) {
        addUserView = view
    }

    public void onSomethingClicked() {

        UserInfo userInfo = addUserView.GetUserInfo();
        // etc.
    }
}

Чим це відрізняється від UserInfoпрямого перегляду у подання за допомогою обробника подій? Основна відмінність полягає в тому, що ведучий все ще несе відповідальність за логіку, яка спричиняє створення UserInfoоб'єкта. тобто подія дійшла до Ведучого до створення UserInfo, що дозволяє Ведучому приймати рішення.

Уявіть собі сценарій, коли у вас була логіка ведучого, коли ви не хотіли, UserInfoщоб це створювалося на основі певного стану в області перегляду. Наприклад, якщо користувач не поставив прапорець у вікні перегляду або у вас була перевірка перевірки щодо якогось поля, яке потрібно додати в UserInfo, яке не вдалося - ваш презентатор може містити додаткову перевірку перед викликом GetUserInfo- тобто

    private boolean IsUsernameValid() {
        String username = addUserView.GetUsername();
        return (username != null && !username.isEmpty());
    }

    public void onSomethingClicked() {            

        if (IsUsernameValid()) {
            UserInfo userInfo = addUserView.GetUserInfo();
            // etc.
        }
    }

Ця логіка залишається всередині ведучого, і її не потрібно додавати у вигляд. Якщо вигляд відповідав за виклик, GetUserInfo()то він також відповідав би за будь-яку логіку, пов'язану з його використанням; саме цього намагається уникати модель MVP.

Отже, хоча створений метод, який UserInfoфізично може існувати в класі View, його ніколи не викликають із класу View, а лише з Presenter.

Звичайно, якщо створення UserInfoкінців вимагає додаткових перевірок вмісту віджетів введення користувачем (наприклад, перетворення рядків, валідація тощо), тоді було б краще викрити окремі пристрої для отримання цих речей, так що перевірка / перетворення рядків може зайняти місце в Presenter - і тоді ведучий створює ваш UserInfo.

Загалом, ваша основна мета, що стосується розмежування між Presenter / View, - це гарантувати, що вам ніколи не потрібно писати логіку у поданні. Якщо вам ifз будь-якої причини потрібно буде додати заяву (навіть якщо це ifзаява про стан властивості віджета - перевірка порожнього текстового поля або булева грамота), це належить до презентатора.


1
Чудова відповідь @BenCottrell! Але в мене є ще одна :) Чи є хорошою практикою називати презентаційні методи як onSomethingClicked(), тож коли користувач натискає "щось", Перегляд дзвонить presenter.onSomethingClicked()? Або мої методи презентації повинні бути названі як передбачені дії, в моєму випадку addUser()?
Rômulo.Edu

1
@regmoraes Добре запитання; і я думаю, ви виділили легкий запах у моєму прикладі коду. Звичайно, Presenterце відповідає за логіку інтерфейсу, а не для доменної логіки та спеціально підібрану до View, тому поняття, які повинні існувати, - це концепції інтерфейсу, тому названий метод onSomethingClicked()дійсно підходить. З огляду, названня, яке я обрав у своєму прикладі вище, не пахне цілком правильно :-).
Бен Коттрелл

@BenCottrell По-перше, велике спасибі за чудову відповідь. Я розумію, що це дійсно, якщо цей GetUserInfoметод є у перегляді, як ви згадали (буде ініційовано у ведучого) А як щодо можливих ifумов всередині GetUserInfoметоду? Можливо, деякі поля UserInfo будуть встановлені через реакцію користувача? Сценарій: Можливо, користувач встановить прапорець, тоді деякі нові компоненти (можливо, новий EditText) будуть видимі користувачеві. Тож у такому випадку GetUserInfoметод буде мати умову if. GetUserInfoЧи дійсний цей сценарій ?
blackkara

1
@Blackkara Розглянемо трактування UserInfoяк модель перегляду (він же "Перегляд моделі") - У цьому сценарії я додав би booleanстан прапорця та порожній / зведений Stringстан текстового поля в UserInfo. Ви можете навіть розглянути можливість її перейменування, UserInfoViewModelякщо це допоможе подумати про те, що POJO є класом, єдиною реальною метою якого є дозволити UserInfoPresenterз'ясувати інформацію про стан перегляду.
Бен Коттрелл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.