Страницы

Поиск по вопросам

понедельник, 26 ноября 2018 г.

Интерфейсы в MVP

Это наверное тысячный вопрос по MVP. Перечитал очень много статей, пересмотрел многие исходники из GitHub. Но мне до сих пор не понятны некоторые вещи. И исходя из одного примера погрузился в MVP, уже не помню название туториала. Но не в этом суть.
Вот пример где практикую с MVP. Структура такова:

Где IChatsInteractor.java:
public interface IChatsInteractor { void getChatsByCount(int count, IChatsCallback chatsCallback);
interface IChatsCallback{ void onSuccess(ChatsModel chatsModel);
void onFailure(String errorMessage); } }
А ChatsInteractorImpl реализовывает IChatsInteractor и подтягивает данные с сервера. Полученные данные записывает в RealmDB и возвращает полученные данные в методе ichatsCallback.onSuccess, ichatsCallback.onFailure если ошибка.
Работает все это корректно. Но проблема в том, что я даже понятия не имею что вообще значит слово interactor (из урока начал использовать). Хочу переименовать, но никак не пойму как, на какое название и т.д.
Вопросы:
Правильно ли то, что из за одного Activity (ChatsActivity) создал 5 классов: (ChatsView - он нужен, понимаю, ChatsInteractorImpl - работает с сервером.) Остальные 3 класса нельзя ли как то объединить или так правильно? Как видите для интеракторов создал отдельный пакет. Можно ли его запихнуть в папку model? Как правильно переименовать интеракторов на название основываясь на его функции? Стоить ли вытаскивать функцию записи полученных данных в базу данных из метода getChatsByCount() в классе ChatsInteractorImpl? И вообще, правильно ли я структурировал (спроектировал) весь MVP, то есть классы, методы?


Ответ

Очень спорный вопрос, нет, это не значит, что он плох, даже наоборот - откровенно всё пишите. По вопросом, мне кажется понимаете правильно, я просто немного попытаюсь помочь. Я люблю вопросы по архитектуре, потому что даже Google колбасит, а различий множество MVP, MVI, MVB, MVVM, MVVSP, VIPER... Не говоря, о том что популярность некоторых полностью или частично меняет структурные решения. Но самое интересное, что действительно каждому, есть место быть, если разработчик считает, что это действительно удобно, во всех направлениях.
Если у вас всё хорошо помещалось в 1 activity, вы легко тестировали этот компонент и легко добавляли новые фичи или даже они не нужны в будущем, то возможно вы излишне использовали MVP. Да, именно так!, я видел множество мелких проектов, которые писали под разные решения, состоящие из несколько простых activity, и действительно тот же MVP там смотрится ужасно. Но! для больших проектов в activity могут использоваться и больше кол-во классов, десятки и сотни и так далее. Вот тогда это будет вашим спасением и во время добавления фичи, вы будете чувствовать себя комфортно, а сторонние разработчики намного быстрей смогут понять идею и приступить к помощи. Объединить можно...., например обернуть фасадом интерфейсы и это смотрится хорошо и редактирование удобное для MVP Действительно интеракторы совмещают с моделью, но тогда модель быстро раздувается, и становится сложно тестируемой и заменяемой. Сейчас есть решения для таких ситуаций и это наверное отдельная тема. Dagger 2 к примеру с Rx, делает эту прослойку незаметной. Если и всё-таки решили так сделать, то модель должна предоставить необходимые данные а вот сама функция, как и всегда по codeStyle должна - быть говорящей. Нет, интеракторы являются посредниками между P и M , и это его задача осуществить нужный запрос от необходимых менеджеров, для получения или записи данных в модель и оповещать presenter о действиях, но это суть, на практике очень сильно бывает размыта. Возможно. По package и нескольким классам тяжело сказать.
UPDATE:
Сразу не увидел link на GitHub, что я могу добавить. Структуруа нормальная, хотя мне кажется MVP уже так мало кто использует, такой примитивный вариант, голый я бы сказал, хотя для понимания так и должно происходить. А вот используете, а точней не используете MVP, рассмотрим на примере LoginActivity.
@Override protected void onStart() { super.onStart(); Realm realm = Realm.getDefaultInstance(); RealmResults accessDM = realm.where(AccessDataModel.class).findAll();
if (accessDM != null) { AccessDataModel accessDataModel = accessDM.get(0); final String string = accessDataModel.getAccessToken() + "
" + accessDataModel.getUserId() + "
" + accessDataModel.getExpiresIn();
Intent intent = new Intent(this, ChatsActivity.class); intent.putExtra("data", string).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish(); }
realm.close(); }
CodeStyle упустим. Самое плохое, что вы смешали бизнес логику с View, не смотря на то что вы построили MVP, вы продолжаете все делать в Activity. Давайте рассмотирм один вариант на вашем примере: LifeCycle метод onStart() очень показательный. #109 line number
Кратко. Вы берете instance Realm, проверяете какие-то данные на доступ, если данные есть - формируете String и переходите в ChatActivity. Как примерно должно быть: Когда срабатывает onStart Activity() вы просто сообщаете презентору об этом. И ваш метод должен выглядеть примерно так:
@Override protected void onStart() { super.onStart(); mPresenter.onActivityStarted(); }
Замечу, что плохим тонном считается дублировать колбеки жизенного цикла компонентов 1 в 1:
Плохо:
@Override protected void onDestroy() { presenter.onDestroy(); super.onDestroy(); }
они должны для презенторов нести логику, но также нужно сходу отличать название, ибо когда другой компонент будет вызвать аналогичный метод или Fragment, вам придется не только переименовать, но и переходить внутрь, чтоб понять, что куда. Более того заметьте что вы вызываете презентер перед супер методом, тоже сомнительно, ибо если есть базовые классы или измененные State, может полвиять на логику работу в презентере то можете словить Leak.
в Presenter должно быть примерно так:
@Override public void onActivityStarted() { boolean ifAccess = getInteractor.getAccess(); if (ifAccess) getMvpView().navigateToChatsActivity(getInteractor.getAccessToken); else getMvpView().showAccessDenied(); }
во View если доступ есть:
@Override public void navigateToChatsActivity(String accessToken) { Intent intent = new Intent(this, ChatsActivity.class); intent.putExtra("data", accessToken).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish(); }
если нет:
@Override public void showAccessDenied() { Toast.makeText(this, "AccessDenied", Toast.LENGTH_LONG).show(); }
А интерактор разбирается с instance realm, и выполняент работу асинхронно. У меня в примере, более примитивно, чтоб вы уловили суть MVP, особенно если вы не работаете c Rx.

Комментариев нет:

Отправить комментарий