Pull to refresh

Comments 19

Я уж думал, что в русскоязычном сообществе Android разработчиков эта тема никого не интересует. Статья хорошая, но два небольших момента:

  • debounce — это не директива, а оператор, в терминологии Rx
  • Введённые интерфейсы в данном примере — интерфейсы ради интерфейсов, никакого смысла вводить их без нескольких реализаций нет, а рефакторинг в IDE позволяет легко сделать это при необходимости


Пишите ещё :)
Ну, если так судить, то почему тогда Вас не смущает самое наличие MVP в примере без тестов?) Абстракция ради абстракции ведь! Подумаешь, тот же код из onCreate, но раскидали по классам с модными названиями, зачем пыжились? Нет, если я правильно думаю и автор не угомонит свои таланты, то нас ждут логичные продолжения с DI и тестами, где как раз и заиграют красками интерфейсы. По крайней мере, я очень на это надеюсь, потому что начало хорошее, а пробуя писать тесты для Rx в последний раз я чувствовал боль.
Ну как бы, ничего не мешает писать тесты без интерфейсов, конечно, если вы не будете объявлять все методы как final, если говорить о юнит тестах с моками (mockito, например).

Логичные продолжения с DI, да, было бы не плохо просветить людей, особенно, если это будет Dagger 2.

Тесты с Rx пишутся на раз два, гораздо удобнее, чем для коллбек-ориентированной асинхронщины, т.к. вы можете выполнить Observable в текущем потоке — toBlocking().

Ваш стиль наезда меня позабавил, спасибо :)
А какие-то чуть более примитивные примеры использования rx в Android может кто-нибудь привести? Я догадываюсь, что в интерфейсе Idea без этого явно не обошлось. Но большинство задач ui: ввести что-то -> отправить на сервер и загрузить что-то -> отобразить. Зачем rxJava в подобных задачах?
Вы можете решать эти задачи, используя RxJava, будет элегантно (особенно с лямбдами) и дополняемо/изменяемо.
А в чем соль? Там нет каких-либо зависимостей, как правило, и/или пересчетов. Не очень понимаю зачем.
Например, вы хотите преобразовать результат запроса в нечто другое, или объединить один асинхронный запрос с другим, для таких задач RxJava очень хороша.
Задача работы с сетью в рамках android-а предполагает наличие отдельного патока и его правильного старта, учитывающая повороты, закрытие экрана. Далее идут задачи по обработке отсутствие сети (как, в общем-то, было указано в статье) и т.д

Все выше сказанное проистекает из одного факта, задача ввести что-то -> отправить на сервер и загрузить что-то -> отобразить не является такой уж тривиальной, как может показаться на первый взгляд.

Так как Model и View используют одни и тебе виджеты (в нашем случае EditText и TextView) для своей работы, разумно будет реализовать содержащий их класс.ExampleViewHolder.java:

Недопустимо ссылаться на виджеты равно как на любую UI или Presenter специфик логику из модели, теряется весь смысл концепции MVP. В идеале части M V и P разделены на отдельные модули и имеют односторонние зависимости M <= P <= V.
В данном случаи ссылаются на одни и те же UI элементы конкретные реализации, поэтому действительно фраза не совсем верная, хотя дальше видно по примеру что имелось ввиду.

По поводу разделение — оно делается, что бы представить программу в простом линейном виде: получение данных -> обработка данных -> отображение данных

Так как UI элементы в данном случаи будут выступать и как источник данных и элементы для отображение, то ссылки естественно возникают в реализации Model и View, Presenter связывает Model с View.

В итоге получаем схему:

Presenter {
   Model model = ...
   View view = ...
   
   onCreate(...) {
       model.getData(...).flatMap(...).subscribe(view.show());   
   }
}

Так как UI элементы в данном случаи будут выступать и как источник данных и элементы для отображение, то ссылки естественно возникают в реализации Model и View, Presenter связывает Model с View.


Нет, это уже не MVP и с ним общего ничего не имеет, кроме названий классов. Что вы будете делать, когда вам понадобится сделать версию под планшет, где, предположим, из-за особенностей UI придётся использовать совсем другие виджеты? Т.е. я ставлю вас перед фактом, что надо поддерживать два набора View с разным набором виджетов. Как вы это организуете в вашем варианте?
Если мы говорим о действительно разном наборе виджетов, что чем вас не устраивает самый тривиальный вариант:
   Model model = isTable ? new TableModelImpl(...) : new PhoneModelImpl(...)
   View view = isTable ? new TableViewImpl(...) : new PhoneViewImpl(...)

   Presenter presenter = new Presenter(model, view);

?
Конечно, Presenter presenter = new PresenterIml(model, view);
DrVirtual прав, нельзя знать про особенности View в модели, вообще. Модель — это слой логики, который работает с данными (в вашей доменной области).

Суть модели именно в том, что она может быть использована откуда угодно, а значит не должна знать специфики таких вещей, как View.

Делать две версии модели из-за особенностей Ui — нарушение DRY и здравой логики.
Так в Model вы и не знаете про View ни чего. Две реализации только в том случаи если вы имеете два разных виджета т.е в первом случаи вы получаете текст запроса из edittext-а, а во втором из spinner-а, при этом интерфейс доступа к данным у вас один и тот же, а каждая реализация оборачивает свои UI элементы в Model, представляя общий интерфейс доступа к данным.
Ваше представление об MVP в корне неверно. Либо вы читали такие же некорректные статьи, либо некорректно интерпретировали. У вас даже на КДПВ нет ссылки от Model к View. Хотя и она неверна, т.к. связи должны быть односторонними, а в обратную сторону работа идёт через интерфейсы.
Так в Model вы и не знаете про View ни чего

Вы обманываете, т.к. эти ваши
edittext-а, а во втором из spinner-а
— это часть View.
каждая реализация оборачивает свои UI элементы в Model, представляя общий интерфейс доступа к данным.

Я не занимаюсь разработкой под Android, но в идеальном варианте ни Model, ни Presenter не имеют доступа ни то, что к View, но и к пакету android в принципе, т.е. они не знают, что работают под android'ом. И уж особенно нельзя нарушать правила разделения зависимостей между M, V и P — код в разных модулях и зависимости между ними настроены односторонне M<=P<=V, это принципиально.

MVP это про распределение обязанностей и зависимостей, в вашем случае реализация примера должна иметь следующий вид:
Пакет Model:
класс с данными ExampleModel
Пакет Presenter:
интерфейс ExampleView с методом updateResponse(String response)
класс ExamplePresenter'а с методами doRequest(String response)
Пакет View:
класс-реализация интерфейса ExampleView

ExampleView дёргает ExamplePresenter.doRequest, ExamplePresenter устанавливает в ExampleModel данные запроса, и делает запрос на сервер, когда получает ответ, то устанавливает его в ExampleModel и дёргает метод интерфейса ExampleView.updateResponse.

Также важно выделять весь View в отдельный пакет и обращаться только через интерфейсы, т.к. это позволит делать unit тесты, подменив реализации на тестовые.

150 человек добавило эту статью в избранное — кто-то мог воспринять её серьёзно. Рекомендую удалить её пока, ознакомиться с темой более внимательно и написать действительно полезную статью. В качестве хорошей реализации MVP рекомендую ознакомиться с реализацией на www.mvcsharp.org (она на c#, но смысл от этого не меняется). Плюс там есть несколько статей на эту тему. Можете консультироваться, если будут вопросы.
Хорошо, тогда я проконсультируюсь у вас по поводу корректной реализации и внесу необходимые правки в статью.
Добавил пояснения по терминологии и с ссылкой на пример, вами провалидированный.
Sign up to leave a comment.

Articles