Comments 48
Спасибо, очень хорошая статья, достаточно детально описано. Конечно, проблема MVP в том, что каждый понимает его по-своему (есть куча реализаций этого паттерна), предложенная схема в принципе одна из самых распространненых. Надеюсь, что вторая часть (особенно про тестирование будет также интересна).
Немного замечаний: не совсем понимаю выделение в интерфейс базового презентера — ведь как интерфейс он нигде не используется. Базовый класс презентера — это да, общая функциональность. А вот интерфейс — просто лишний.
И насчет извечной боли — как и утечек избежать, и запрос нормально сделать, тут есть спорные моменты. При вызове onStop у вас подписка отписывается, запрос отменяется. Отсюда следует, что при поворотах и прочем менеджить переподпиской придется самому. Альтернатива — использовать презентер для взаимодействия с лоадерами или с сервисом, но тут свои минусы: в таком случае презентер уже будет знать о классах андроида. Впрочем, тестированию это особо не мешает.
P.S. Есть канал по паттернам, где 90% обсуждений посвящено MVP, можно присоединяться :)
Немного замечаний: не совсем понимаю выделение в интерфейс базового презентера — ведь как интерфейс он нигде не используется. Базовый класс презентера — это да, общая функциональность. А вот интерфейс — просто лишний.
И насчет извечной боли — как и утечек избежать, и запрос нормально сделать, тут есть спорные моменты. При вызове onStop у вас подписка отписывается, запрос отменяется. Отсюда следует, что при поворотах и прочем менеджить переподпиской придется самому. Альтернатива — использовать презентер для взаимодействия с лоадерами или с сервисом, но тут свои минусы: в таком случае презентер уже будет знать о классах андроида. Впрочем, тестированию это особо не мешает.
P.S. Есть канал по паттернам, где 90% обсуждений посвящено MVP, можно присоединяться :)
UFO just landed and posted this here
А аргументы? :-)
Поясните?
Чего минусите то человека? Дело говорит. Посмотрите на количество файлов и связность.
Ну, заявиться и сказать, что кг/ам (образно), — дело плевое.
А вот привести конкретную аргументацию на ресурсе, который посещают в том числе и новички, — силушки не хватило :)
А вот привести конкретную аргументацию на ресурсе, который посещают в том числе и новички, — силушки не хватило :)
Нарисуете свою схему именно для этого примера?
Я не умею рисовать схемы (шутка) =) Но на словах: зачем три файла/класса для презентера? Зачем интерфейс Presenter (если там lifecycle callback методы, то и назовите его LifecycleCallbacks по аналогии с ActivityLifecycleCallbacks)? А абстрактный BasePresenter, чтобы от CompositeSubscription отписываться? Увеличение абстракции оправдано, если вы пишете какой-нибудь фреймворк или библиотеку. Или это делается потому что так написано в статьях по MVP? Задайте себе вопрос: как часто вам приходилось выкидывать один презентер и заменять его на другой? Мне, например, ни разу.
Что касается Model слоя: приложение вообще ничего не должно знать о сущностях DTO, DBO а так далее. Это все лучше вынести в, так называемый, Repository слой. В котором выполняются мапинги данных, принятия решений о том, откуда эти данные брать (из кэша, БД или сети) и так далее. Наружу торчит только Observable<List> getRepoList(String name);
При этом я ни в коем случае не говорю что статья плохая, статья отличная, особенно учитывая их скудное количество в русскоязычном сегменте.
Что касается Model слоя: приложение вообще ничего не должно знать о сущностях DTO, DBO а так далее. Это все лучше вынести в, так называемый, Repository слой. В котором выполняются мапинги данных, принятия решений о том, откуда эти данные брать (из кэша, БД или сети) и так далее. Наружу торчит только Observable<List> getRepoList(String name);
При этом я ни в коем случае не говорю что статья плохая, статья отличная, особенно учитывая их скудное количество в русскоязычном сегменте.
Вот это уже более аргументировано)
По поводу классов презентера соглашусь, но только для данного примера. В общем случае не известно как может пойти развитие.
А вот по сущностям в модели можно обсудить.
Вы предлагаете жёстко привязаться к модели данных.
Возьмём за пример модель RepositoryDTO — в реальности это большая модель с большим количеством полей.
В этом примере слою View надо всего лишь 4 поля. Для этого создаётся отдельный ViewObject — Repository(не путать с вашим паттерном) который содержит только нужные поля, тем самым абстрагируясь от RepositoryDTO и от модели вообще.
Можно предположить, что в будущем измениться апи, скажем c GitHub на GitLab.
В текущем примере нужно поменять маппер Model <->ViewObject. В вашем менять View.
По поводу классов презентера соглашусь, но только для данного примера. В общем случае не известно как может пойти развитие.
А вот по сущностям в модели можно обсудить.
Вы предлагаете жёстко привязаться к модели данных.
Возьмём за пример модель RepositoryDTO — в реальности это большая модель с большим количеством полей.
В этом примере слою View надо всего лишь 4 поля. Для этого создаётся отдельный ViewObject — Repository(не путать с вашим паттерном) который содержит только нужные поля, тем самым абстрагируясь от RepositoryDTO и от модели вообще.
Можно предположить, что в будущем измениться апи, скажем c GitHub на GitLab.
В текущем примере нужно поменять маппер Model <->ViewObject. В вашем менять View.
Вы меня неправильно поняли. Я как раз об этом и говорил. Есть некоторые сущности, которые являются ViewObject, при этом откуда она была получена, нам абсолютно неважно. Получение же этого ViewObject логично вынести в слой, который я назвал Repository, роль которого в контексте статьи выполняет ApiInterface. Просто я предлагаю скрыть всю реализацию мапингов и прочих манипуляций внутри реализации ApiInterface и наружу выдавать уже готовые ViewObject модели. В статье же это делается на уровне презентера.
getRepoList() {
return retrofit.getRepoList().flatMap({Model -> ViewObject});
}
Я понял, можно, но это если View чётко соответсвует одной модели, а если нет?
Например, есть 2 Активити, которым нужна одна модель, но разные поля из неё т.е. для разных View, ViewObject будут разные, хоть и будут абстрагировать одну модель.
У вас получится, что слой Repository будет иметь методы getViewObject1() и getViewObject2().
В примере автора, о конкретном ViewObject будет знать только соответствующая конкретная реализация Presenter, что на мой взгляд несколько правильнее.
Например, есть 2 Активити, которым нужна одна модель, но разные поля из неё т.е. для разных View, ViewObject будут разные, хоть и будут абстрагировать одну модель.
У вас получится, что слой Repository будет иметь методы getViewObject1() и getViewObject2().
В примере автора, о конкретном ViewObject будет знать только соответствующая конкретная реализация Presenter, что на мой взгляд несколько правильнее.
Спасибо за замечания!
1) Интерфейс Presenter в данный момент получился лишним, с этим я полностью согласен.
2) Абстрактный BasePresenter содержит в себе функцию управления подпиской, реализовывать это в каждом презентере = дублировать код.
3) Model слой и DTO. Тут палка о двух концах, с одной стороны независимость приложения от DTO, DBO и прочих моделей (которая в данный момент достигается за счет мапперов), с другой стороны жесткая связка Model (DataRepository) и прикладного приложения.
В данный момент в слое Model нет ни одного импорта из Presenter или View, мы можем перенести весь слой в другое приложение, он полностью независим. Также, как было сказано выше, при изменении model нужно переписать мапперы, View Object (а вместе с ними и остальной код) при этом не изменятся.
1) Интерфейс Presenter в данный момент получился лишним, с этим я полностью согласен.
2) Абстрактный BasePresenter содержит в себе функцию управления подпиской, реализовывать это в каждом презентере = дублировать код.
3) Model слой и DTO. Тут палка о двух концах, с одной стороны независимость приложения от DTO, DBO и прочих моделей (которая в данный момент достигается за счет мапперов), с другой стороны жесткая связка Model (DataRepository) и прикладного приложения.
В данный момент в слое Model нет ни одного импорта из Presenter или View, мы можем перенести весь слой в другое приложение, он полностью независим. Также, как было сказано выше, при изменении model нужно переписать мапперы, View Object (а вместе с ними и остальной код) при этом не изменятся.
Расскажите как надо, с удовольствием посмотрим и обсудим!
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Для начала оффтоп — чтобы ответить на комментарий есть кнопка «Ответить», не нужно писать новый каждый раз.
Далее, вы куда-то уходите от идеи, C# тут появился уже:)… можете дать конкретный пример, ссылки?
Скажем есть база данных, простейшая. Есть экран со списком и с кнопкой, по нажатию идёт запрос в базу и заполняется список.
Какие ноды куда мне надо привязывать?
Далее, вы куда-то уходите от идеи, C# тут появился уже:)… можете дать конкретный пример, ссылки?
Скажем есть база данных, простейшая. Есть экран со списком и с кнопкой, по нажатию идёт запрос в базу и заполняется список.
Какие ноды куда мне надо привязывать?
Шизофрения какая-то в комментах пошла…
UFO just landed and posted this here
UFO just landed and posted this here
Товарищ, вы пишете, совершенно не разбираясь в теме. Каким образом то, что возвращает rest api поможет построить архитектуру android-приложения? Вы предлагаете в java вместо классов для модели хранить все в json? Не говоря об отвратительной скорости работы с этим (по сравнению с POJO), как вообще json может заменить нормальные, человеческие java-классы?
Дайте пример?) Или вы, сударь, трепло?)
UFO just landed and posted this here
Классы те же объекты, только избыточные.
Wat??
Плохо приспоcбленные для разборки и сборки. Поэтому выдуваются всяческие костыли в виде DI.
Как связаны dependency injection и сборка/расборка объектов? Что такое вообще сборка объектов?
Причём тут REST API????
При том, что в статье идет речь о запросах к api, которые возвращают json.
Ощущение, что вы понятия не имеете о разработке на java и под android. Или просто троллите всех.
И да, используйте кнопку «Ответить».
UFO just landed and posted this here
JSONPath этот ваще для школоты, а от XPath аж тошнит.
Стоит упомянуть, что пьяным заходить на хабр не стоит. Причем здесь дисплей-листы? Это вообще поприще компьютерной графики.
Скрытый текст
А на гитхабе у jsonpath читаем:
Как он мог такое предложить, объекты — это же фу-фу-фу, слой модели должен состоять из json-ов!
If you configure JsonPath to use the JacksonMappingProvider you can even map your JsonPath output directly into POJO's.
Как он мог такое предложить, объекты — это же фу-фу-фу, слой модели должен состоять из json-ов!
UFO just landed and posted this here
Экась вы ловко со слоя model на view перескочили. Точно тролль.
То есть, вы gui на чистом opengl реализовываете? Понятно, почему вы такой нарезанный. Вас остается только пожалеть.
Но все же вернитесь к нашимбаранам json-ам, если вам есть, что сказать по существу. И загляните под спойлер предыдущего сообщения. Или это вы так ловко обходите неприятные вам углы?
То есть, вы gui на чистом opengl реализовываете? Понятно, почему вы такой нарезанный. Вас остается только пожалеть.
Но все же вернитесь к нашим
Вы не нервничайте — и не будете промахиваться по кнопке «Ответить» :) Это ведь не удобно, вот вам пример)
По делу, официальную документацию к чему надо читать? Открыл документацию по Андроиду — вашу тему не нашёл.
По делу, официальную документацию к чему надо читать? Открыл документацию по Андроиду — вашу тему не нашёл.
UFO just landed and posted this here
Честно говоря, я давно так не смеялся читая комментарии :)
Sign up to leave a comment.
Построение Android приложений шаг за шагом, часть первая