"Описал выше" это прямо в том же комменте. Неужели не заметно было?
Вот:
Суть в том, что есть 2 паттерна. Не один. Два. И мы сравнивая их видим отличие только в отношении связывания: "автоматическое" ли оно.
В нашем понимании в MVVM да, тк там фреймворк позволяет тебе не писать бойлерплейт код, а в PM нет, тк его приходится писать.
Ответил? Тогда жду ответ на вопрос:
является ли связывание при помощи listener'а автоматическим.
Из ваших комментов получается, что связывание автоматическое всегда. И нигде не происходит автоматически. Тем самым вы отрицаете само существование паттерна PresentationModel и при этом еще и приводите Фаулера в доводы.
Вам нужно еще более "автоматически"?
Да, в Databinding Library и других это происходит еще более автоматически.
Теперь вернемся к Фаулеру:
Probably the most annoying part of Presentation Model is the synchronization between Presentation Model and view. It's simple code to write, but I always like to minimize this kind of boring repetitive code. Ideally some kind of framework could handle this, which I'm hoping will happen some day with technologies like .NET's data binding.
В статье же Джона Гроссмана, которую указал Mujahit, тот продолжает
WPF has done exactly that by including a very rich powerful data-binding engine. Basically, in the past all of these frameworks worked using the Observer or Publish/Subscribe pattern. In the simplest version the Model publishes change notifications and the View subscribes and updates itself in response to events. Not only is this code repetitive, but it can be a source of bugs and perf problems. The data binding engine in Avalon just automates all that work, and provides 2-way binding to boot that minimizes how much work you have to do to push changes from the View back into the Model.
Никаких знакомых слов не заметили? Выделю:
The data binding engine in Avalon just automates all that work
Еще немножечко сокращу:
automates all that work
Итак:
Мы понимаем различие между MVVM и PM как его понимают создатели этих паттернов.
В наличии автоматического databinding'a. Чего-то, что позволяеет упростить написание кода для связывания.
Вы же не станете отрицать, что написать в XML поле от которого зависит виджет проще, чем писать то, что приходится в приведенном нами паттерне?
Я отвечу — конечно проще.
Ведь, код, необходимый для связывания появится автоматически.
Исходя из всего сказанного, паттерн, описанный в статье, раз в нем надо писать код связывания самому и нет никакого фреймворка делающего за тебя эту работу, ближе к PM.
Вопрос был о том, является ли связывание при помощи listener'а автоматическим.
Вы же ответили
Оповещает, конечно.
и зачем-то расписали свой ответ подробнее.
Суть в том, что есть 2 паттерна. Не один. Два. И мы сравнивая их видим отличие только в отношении связывания: "автоматическое" ли оно.
В нашем понимании в MVVM да, тк там фреймворк позволяет тебе не писать бойлерплейт код, а в PM нет, тк его приходится писать.
Связывание есть и там и там. Поэтому обсуждать databinding не вижу смысла.
Если хотите продолжать обсуждение, давайте вернемся к вопросу о понимании слова "автоматически".
Я выше написал, что понимаю под этим, а что вкладываете в это понятие вы?
А обычный listener оповещает не автоматически?
Тогда PM вообще не существует как паттерн и есть только MVVM.
Ну что ж, ок, только не говорите об этом Фаулеру, не расстраивайте человека ;)
Судя по всему, тк он мог "конфликтовать" с докладом Степана Гончарова и Дениса Неклюдова.
Хотя по-моему это не так. В их подходе используется обычный MVVM c Databinding Library, да и доклад был про подход к архитектуре в приложении в целом, а не только о презентационном паттерне. Поэтому, я думаю, конфликта не было бы. Но, что сделано, то сделано. Зато статья вышла быстрее ;)
Не путайте людей, пожалуйста.
Прочтите статьи по ссылкам. В описании паттерна Presentation Model все очень доступно описано.
Суть отличия не просто в наличии databinding'а. Он есть и там и там. Data binding в прямую переводится как связывание данных. Без этого все паттерны были бы бесполезны.
Отличие — в наличии автоматического датабиндинга.
В случае с PM его не было. И позже, в WPF его добавили (позже). То есть MVVM развился из PM
Поэтому называть PM как MVVM это как называть мотоцикл автомобилем.
1) Думаю тут проблема не в либе и не в том, что надо восстанавливать команды. Не надо. Нужно разобраться почему не восстанавливается нужный фрагмент. Он должен восстанавливаться силами FragmentManager и android. Ищите проблему в своей реализации. Потому что то, о чем говорите вы все верно отрабатывает в sample-приложении. Можно уйти далеко по стеку фрагментов и повернуть и все восстановится. Силами cистемы. Даже при включенном "не сохранять действия".
2) Я понимаю, что вы хотели сделать. Реализовать сохранение состояния стека экранов сохраняя последовательность навигационных команд. Как Moxy cохраняет состояние вью. Но это задача для отдельной либы или форка. Мы же наоборот хотели, чтобы либа была простой. Если нужно что-то более сложное — посмотрите в сторону Flow и Conductor.
3) Библиотека не держит очередь в себе. Это было изначальной мыслью при ее создании. Она дает интерфейс команд, механизм их комбинирования и пересылки. Все. Реализовать команды, хнанение стека экранов, восстановление стека — это все задачи за переделом ответственности библиотеки. В случае с фрагментами все уже сделано в андроиде, а мы даем дефолтную имлементацию навигатора. В случае с вьюхами это надо будет все делать самостоятельно. Либо силами другой либы.
Но при пересоздании активити они не повторяются, т.е. мы теряем преимущество Moxy с их очередью команд.
Что-то не совсем понятно, что вы имеете в виду, можете описать иначе?
Попытка переопределить Router и добавить очередь.
Очередь невыполненных команд живет в CommandBuffer. Для чего вам очередь в рутере?
А также необходимо очищать очередь в случае смены rootScreen.
А для чего?
Из того что я понял, вы пытаетесь восстановить состояние стека экранов при помощи Cicerone, а состояние экрана средствами Moxy. Но зачем вам это если FragmentManager и так восстановит состояние бекстека я не понимаю. Или вы делаете без фрагментов?
Этих четырёх команд на практике достаточно для построения любых переходов
Тут скорее имелось в виду, что их достаточно для построения практически любых переходов.
Конечно, может появиться какой-то специфический кейс, который будет удобнее решить по-другому.
И для этого можно всегда легко добавить свою команду. И сделать свой вариант роутера, в котором добавить переход, использующий эту команду или комбинирующий её с остальными. Но сперва надо посмотреть нельзя ли решить этот кейс встроенными командами (мы же все ленивые).
Для меня самое прекрасное в либе как раз то, что она маленькая и гибкая.
В контексте этой статьи хочется привлечь внимание к тому, как часто люди называют свои реализации паттернов не теми именами. Это, конечно, не страшно, но создает путанницу.
Так, к примеру, сейчас очень часто можно встретить описание решений типа "какой-то там MVVM". Начинаешь читать и понимаешь, что в этом решении не автоматический датабиндинг, а создается какой-то свой вид биндинга. Но, MVVM - automatic databinding = PresentationModel, а люди упорно называют это MVVM.
Я надеюсь, что прочитав эту статью вы увидите разницу между этими паттернами и присоединитесь ко мне в том, чтобы называть вещи правильными именами. Хотя бы как дань уважения создателям этих паттернов.
В одном подкасте один разработчик рассказывал, что в MVVM когда используется несколько ViewModel, зависящих друг от друга, то используется controller над ними.
К примеру, строка поиска со своей VM, а карточка с результатом со своей. И вот мы нажали поиск в строке поиска и нам надо отобразить прогресс в карточке. Передача этого действия будет через их общий controller.
Есть, конечно, разные пути сделать то же самое. Но я вспомнил это, прочитав ваш пример. Получается, что и в правду, описанный вами подход составляет MVVM в одном из видов реализации связи между VM. В подкасте речь была вроде про WPF.
«логически» определяет, что данный Component будет жить столько же, сколько Scope.
Да, умирает компонент и вместе с ним все, что он в себе содержал. Все элементы отмеченные scope.
Т.е., создав Component внутри Fragment, при повороте экрана Component также будет уничтожен
Конечно. Сам component не во фрагменте. Обычно хранят в Application или можно в своем синглтоне. Как нравится.
Но в таком случае можно не заморачиваться и хранить в Синглтоне сразу ViewModel.
В смысле не используя dagger? Можно. Но если уже юзаешь его в проекте, то с ним удобно.
В общем схема примерно такая: в Application лежит component, в котором лежит VM. Когда происходит поворот мы проверяем поворот ли это и если да, не делаем ничего. Если это не поворот, а фрагмент умирает, то обнуляем component. И в следующий раз получаем уже новую VM из нового component.
Это я описал грубо, для общего понимания схемы. В реальности у нас много фрагментов и много VM, поэтому убивать весь component плохо. И поэтому в компоненте хранится образно мапа вьюмоделей, и обнуляется VM в ней когда умирает фрагмент.
Да, но без приставки "авто" это уже паттерн Presentation Model. И как раз к нему у меня претензий вообще нет ;)
А так, я с вами не спорю. В статье я вроде пару раз сказал, что выводы носят отчасти субъективный характер. То как приходится работать мне не по душе. К этому добавляются еще и ограничения платформы и библиотеки.
Спасибо за коммент. А я про проблему с тем, что нужно писать boilerlate не используя ObservableField и не писал ;)
В простых случаях можно использовать ObservableFields, да. Но когда надо сделать связи между полями (где вы предлагаете использовать Rx), можно наследоваться от BaseObservable и настроить связи там.
А чтобы не делать в одном случае так, в другом так я предпочитаю чаще использовать второй вариант.
Спасибо за комментарий с информацией!
Нет, в Databinding Library нет триггеров. Но это не сложно реализовать самим.
В любом случае это мне и не нравится, что кроме автобиндинга приходится использовать запросы от VM к V.
Спорный момент. Логика отображения — это как раз то, что должно быть в VM. Все эти паттерны созданы для выноса логики отображения из View, чтобы можно было тестировать и заменять View. А раз логика обработки ошибок попала во View, то захотев подменить View на другую, нам придется в другой прописывать ту же логику обработки ошибок.
И чтобы не путаться, уточню, что я говорю про логику, а не про визуальный элемент, отображающий ошибку.
Да и кроме ошибок есть еще и системные вещи, типа задержек и тп. К примеру, в одном случае я хочу вывести текст с задежкой в 2 секунды, а в другой 3, и тд. Получается, что это попадет во вью? Вью будет содержать по обработчику для каждой ситуации? Или в обработчике будет параметр?
Тогда это похоже на метод. А тогда мы приходим к тому, что надо вызывать его. И отсюда к проблеме двойственности. Вызов метода и автодатабиндинг.
В MVP состояние View устанавливается вызовом набора команд на интерфейсе View. И если хранить этот стек вызвовов этих команд и применить их на вновь приаттаченой вью, то эта проблема решается. Но это для MVP красиво именно потому, что там используются методы для установки состояния вью, а не поля.
Не совсем. Скорее в рамках всех инструментов (которые я знаю на данный момент) это красиво сделать не удается. Во всяком случае, я пока не слышал о фреймворке, который решал бы красиво те проблемы, которые я описал.
Я бы и рад узнать о таком, потому что мне нравится сам паттерн MVVM.
Это оно тебя заставило ;)
Мы тут спорим или общаемся?
"Описал выше" это прямо в том же комменте. Неужели не заметно было?
Вот:
Ответил? Тогда жду ответ на вопрос:
Из ваших комментов получается, что связывание автоматическое всегда. И нигде не происходит автоматически. Тем самым вы отрицаете само существование паттерна PresentationModel и при этом еще и приводите Фаулера в доводы.
Да, в Databinding Library и других это происходит еще более автоматически.
Теперь вернемся к Фаулеру:
В статье же Джона Гроссмана, которую указал Mujahit, тот продолжает
Никаких знакомых слов не заметили? Выделю:
Еще немножечко сокращу:
Итак:
Мы понимаем различие между MVVM и PM как его понимают создатели этих паттернов.
В наличии автоматического databinding'a. Чего-то, что позволяеет упростить написание кода для связывания.
Вы же не станете отрицать, что написать в XML поле от которого зависит виджет проще, чем писать то, что приходится в приведенном нами паттерне?
Я отвечу — конечно проще.
Ведь, код, необходимый для связывания появится автоматически.
Исходя из всего сказанного, паттерн, описанный в статье, раз в нем надо писать код связывания самому и нет никакого фреймворка делающего за тебя эту работу, ближе к PM.
Вы пишете так много, что уже сами теряете нить.
Вопрос был о том, является ли связывание при помощи listener'а автоматическим.
Вы же ответили
и зачем-то расписали свой ответ подробнее.
Суть в том, что есть 2 паттерна. Не один. Два. И мы сравнивая их видим отличие только в отношении связывания: "автоматическое" ли оно.
В нашем понимании в MVVM да, тк там фреймворк позволяет тебе не писать бойлерплейт код, а в PM нет, тк его приходится писать.
Связывание есть и там и там. Поэтому обсуждать databinding не вижу смысла.
Если хотите продолжать обсуждение, давайте вернемся к вопросу о понимании слова "автоматически".
Я выше написал, что понимаю под этим, а что вкладываете в это понятие вы?
А обычный listener оповещает не автоматически?
Тогда PM вообще не существует как паттерн и есть только MVVM.
Ну что ж, ок, только не говорите об этом Фаулеру, не расстраивайте человека ;)
Судя по всему, тк он мог "конфликтовать" с докладом Степана Гончарова и Дениса Неклюдова.
Хотя по-моему это не так. В их подходе используется обычный MVVM c Databinding Library, да и доклад был про подход к архитектуре в приложении в целом, а не только о презентационном паттерне. Поэтому, я думаю, конфликта не было бы. Но, что сделано, то сделано. Зато статья вышла быстрее ;)
Не путайте людей, пожалуйста.
Прочтите статьи по ссылкам. В описании паттерна Presentation Model все очень доступно описано.
Суть отличия не просто в наличии databinding'а. Он есть и там и там. Data binding в прямую переводится как связывание данных. Без этого все паттерны были бы бесполезны.
Отличие — в наличии автоматического датабиндинга.
В случае с PM его не было. И позже, в WPF его добавили (позже). То есть MVVM развился из PM
Поэтому называть PM как MVVM это как называть мотоцикл автомобилем.
Спасибо за такую высокую оценку! Очень приятно.
А вам быстро разобраться, в чем проблема и приятного кодинга!
1) Думаю тут проблема не в либе и не в том, что надо восстанавливать команды. Не надо. Нужно разобраться почему не восстанавливается нужный фрагмент. Он должен восстанавливаться силами FragmentManager и android. Ищите проблему в своей реализации. Потому что то, о чем говорите вы все верно отрабатывает в sample-приложении. Можно уйти далеко по стеку фрагментов и повернуть и все восстановится. Силами cистемы. Даже при включенном "не сохранять действия".
2) Я понимаю, что вы хотели сделать. Реализовать сохранение состояния стека экранов сохраняя последовательность навигационных команд. Как Moxy cохраняет состояние вью. Но это задача для отдельной либы или форка. Мы же наоборот хотели, чтобы либа была простой. Если нужно что-то более сложное — посмотрите в сторону Flow и Conductor.
3) Библиотека не держит очередь в себе. Это было изначальной мыслью при ее создании. Она дает интерфейс команд, механизм их комбинирования и пересылки. Все. Реализовать команды, хнанение стека экранов, восстановление стека — это все задачи за переделом ответственности библиотеки. В случае с фрагментами все уже сделано в андроиде, а мы даем дефолтную имлементацию навигатора. В случае с вьюхами это надо будет все делать самостоятельно. Либо силами другой либы.
Что-то не совсем понятно, что вы имеете в виду, можете описать иначе?
Очередь невыполненных команд живет в CommandBuffer. Для чего вам очередь в рутере?
А для чего?
Из того что я понял, вы пытаетесь восстановить состояние стека экранов при помощи Cicerone, а состояние экрана средствами Moxy. Но зачем вам это если FragmentManager и так восстановит состояние бекстека я не понимаю. Или вы делаете без фрагментов?
Тут скорее имелось в виду, что их достаточно для построения практически любых переходов.
Конечно, может появиться какой-то специфический кейс, который будет удобнее решить по-другому.
И для этого можно всегда легко добавить свою команду. И сделать свой вариант роутера, в котором добавить переход, использующий эту команду или комбинирующий её с остальными. Но сперва надо посмотреть нельзя ли решить этот кейс встроенными командами (мы же все ленивые).
Для меня самое прекрасное в либе как раз то, что она маленькая и гибкая.
Шина данных не несет логики, а этот controller может содержать свою логику. А может вообще быть родительской VM. Так что речь не о шине данных.
В контексте этой статьи хочется привлечь внимание к тому, как часто люди называют свои реализации паттернов не теми именами. Это, конечно, не страшно, но создает путанницу.
Так, к примеру, сейчас очень часто можно встретить описание решений типа "какой-то там MVVM". Начинаешь читать и понимаешь, что в этом решении не автоматический датабиндинг, а создается какой-то свой вид биндинга. Но,
MVVM - automatic databinding = PresentationModel, а люди упорно называют это MVVM.Я надеюсь, что прочитав эту статью вы увидите разницу между этими паттернами и присоединитесь ко мне в том, чтобы называть вещи правильными именами. Хотя бы как дань уважения создателям этих паттернов.
В одном подкасте один разработчик рассказывал, что в MVVM когда используется несколько ViewModel, зависящих друг от друга, то используется controller над ними.
К примеру, строка поиска со своей VM, а карточка с результатом со своей. И вот мы нажали поиск в строке поиска и нам надо отобразить прогресс в карточке. Передача этого действия будет через их общий controller.
Есть, конечно, разные пути сделать то же самое. Но я вспомнил это, прочитав ваш пример. Получается, что и в правду, описанный вами подход составляет MVVM в одном из видов реализации связи между VM. В подкасте речь была вроде про WPF.
Да, умирает компонент и вместе с ним все, что он в себе содержал. Все элементы отмеченные scope.
Конечно. Сам component не во фрагменте. Обычно хранят в Application или можно в своем синглтоне. Как нравится.
В смысле не используя dagger? Можно. Но если уже юзаешь его в проекте, то с ним удобно.
В общем схема примерно такая: в Application лежит component, в котором лежит VM. Когда происходит поворот мы проверяем поворот ли это и если да, не делаем ничего. Если это не поворот, а фрагмент умирает, то обнуляем component. И в следующий раз получаем уже новую VM из нового component.
Это я описал грубо, для общего понимания схемы. В реальности у нас много фрагментов и много VM, поэтому убивать весь component плохо. И поэтому в компоненте хранится образно мапа вьюмоделей, и обнуляется VM в ней когда умирает фрагмент.
Да, но без приставки "авто" это уже паттерн Presentation Model. И как раз к нему у меня претензий вообще нет ;)
А так, я с вами не спорю. В статье я вроде пару раз сказал, что выводы носят отчасти субъективный характер. То как приходится работать мне не по душе. К этому добавляются еще и ограничения платформы и библиотеки.
Спасибо за коммент. А я про проблему с тем, что нужно писать boilerlate не используя ObservableField и не писал ;)
В простых случаях можно использовать ObservableFields, да. Но когда надо сделать связи между полями (где вы предлагаете использовать Rx), можно наследоваться от BaseObservable и настроить связи там.
А чтобы не делать в одном случае так, в другом так я предпочитаю чаще использовать второй вариант.
Спасибо за комментарий с информацией!
Нет, в Databinding Library нет триггеров. Но это не сложно реализовать самим.
В любом случае это мне и не нравится, что кроме автобиндинга приходится использовать запросы от VM к V.
Спорный момент. Логика отображения — это как раз то, что должно быть в VM. Все эти паттерны созданы для выноса логики отображения из View, чтобы можно было тестировать и заменять View. А раз логика обработки ошибок попала во View, то захотев подменить View на другую, нам придется в другой прописывать ту же логику обработки ошибок.
И чтобы не путаться, уточню, что я говорю про логику, а не про визуальный элемент, отображающий ошибку.
Да и кроме ошибок есть еще и системные вещи, типа задержек и тп. К примеру, в одном случае я хочу вывести текст с задежкой в 2 секунды, а в другой 3, и тд. Получается, что это попадет во вью? Вью будет содержать по обработчику для каждой ситуации? Или в обработчике будет параметр?
Тогда это похоже на метод. А тогда мы приходим к тому, что надо вызывать его. И отсюда к проблеме двойственности. Вызов метода и автодатабиндинг.
В MVP состояние View устанавливается вызовом набора команд на интерфейсе View. И если хранить этот стек вызвовов этих команд и применить их на вновь приаттаченой вью, то эта проблема решается. Но это для MVP красиво именно потому, что там используются методы для установки состояния вью, а не поля.
Не совсем. Скорее в рамках всех инструментов (которые я знаю на данный момент) это красиво сделать не удается. Во всяком случае, я пока не слышал о фреймворке, который решал бы красиво те проблемы, которые я описал.
Я бы и рад узнать о таком, потому что мне нравится сам паттерн MVVM.