Статьи

MVC мертв — что будет дальше?

В первой части этой серии был дан обзор ключевых концепций и перечислены некоторые основные преимущества использования методов функционального реактивного программирования в разработке пользовательского интерфейса. В будущих статьях мы сосредоточимся на различных компонентах, которые участвуют, начиная с сегодняшнего дня, с компонента State, ключевого компонента функционально-реактивного программирования пользовательского интерфейса.

data_structures-2-768x432

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

Единый Источник Истины

В приложениях MVC мы обычно различаем модель предметной области и состояние пользовательского интерфейса. Например, если мы реализуем приложение TodoMVC (см. Скриншот ниже), следуя некоторому MVC-шаблону, наша модель, вероятно, будет состоять только из списка записей ToDo, поскольку они определяют наш домен. Но модель не сохранит текущую запись в поле ввода («Что нужно сделать?»). И это, вероятно, также не будет содержать выбранный фильтр.

Скриншот-1-768x407

Скриншот TodoMVC

Компонент State функционального реактивного приложения, с другой стороны, содержит полное состояние приложения. Модель предметной области и состояние пользовательского интерфейса обычно объединяются в единую структуру данных — дерево. Картинка в начале статьи показывает разницу между обоими подходами.

Почему это важно?

Если у нас все состояния в одном месте, то есть в единственном источнике правды, мы можем реализовать представление как чистую функцию.

Это имеет много преимуществ: это легче понять, легче рассуждать и легче тестировать.

неизменность

Второй важной характеристикой государства является его неизменность. Мы не можем это изменить.

Если состояние приложения изменяется, мы должны создать новые структуры данных.

Это может звучать как ужасная трата. Если мы сохраняем все состояние в дереве и нам нужно создавать новый экземпляр каждый раз, когда что-то меняется, как это может быть эффективным? Хитрость в том, что нам не нужно копировать все дерево, а только его небольшую часть.

неизменность-768x432

При изменении одного узла неизменяемого дерева необходимо заменить только небольшое количество узлов.

Представьте, что наши приложения хранятся в дереве, показанном выше. Мы хотим изменить свойство узла зеленого листа. Сам узел изменился, поэтому нам нужно создать новый экземпляр. Нам также необходимо создать новый экземпляр для родительского узла, потому что один из его дочерних элементов изменился. Но другой потомок этого родителя не изменился, и мы можем повторно использовать его, ссылаясь на него из нового родительского узла. То же самое верно для всех других родительских узлов вплоть до корневого узла. Нам нужно создать новый экземпляр для каждого родителя на пути к вершине, но мы можем повторно использовать других потомков. На диаграмме нам нужно только создать новые экземпляры для синих узлов, которые составляют лишь небольшую часть дерева, в частности, если дерево становится огромным.

Реализация состояния в Java

Недавно я начал эксперимент, чтобы исследовать, как принципы функционально-реактивного программирования пользовательского интерфейса могут быть применены к Java и JavaFX. Текущее состояние мини-фреймворка ReduxFX и пример приложения вы можете найти на GitHub.

Реализация компонента State в Java проста. Все элементы состояния могут быть реализованы как простые неизменные POJO.

К сожалению, стандартные коллекции в JDK не очень подходят для неизменяемости. Но, к счастью, есть несколько альтернатив, которые вы можете использовать вместо этого. Моим личным фаворитом на данный момент являются коллекции в Javaslang , которые предлагают несколько дополнительных преимуществ, помимо того, что они неизменны.

Код ниже показывает класс AppModel из примера проекта в ReduxFX. Свойство todos имеет тип Seq, который является частью Javaslang. Seq похож на Iterable в JDK, потому что это супертип всех последовательных структур данных в Javaslang (хотя Seq предлагает гораздо больше функциональных возможностей). Другими словами, todos — это список TodoEntries.

Свойство newTodoText содержит текст, хранящийся в TextField для новых записей todo. И последнее, но не менее важное: фильтр свойств хранит текущий фильтр (ALL, ACTIVE или COMPLETED).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.netopyr.reduxfx.todo.state;
 
import javaslang.collection.Seq;
import org.apache.commons.lang3.builder.ToStringBuilder;
 
public final class AppModel {
 
    private final String newTodoText;
    private final Seq<TodoEntry> todos;
    private final Filter filter;
 
    public AppModel(String newTodoText, Seq<TodoEntry> todos, Filter filter) {
        this.newTodoText = newTodoText;
        this.todos = todos;
        this.filter = filter;
    }
 
    public String getNewTodoText() {
        return newTodoText;
    }
 
    public Seq<TodoEntry> getTodos() {
        return todos;
    }
 
    public Filter getFilter() {
        return filter;
    }
 
    @Override
    public String toString() {
        return new ToStringBuilder(this)
                .append("newTodoText", newTodoText)
                .append("todos", todos)
                .append("filter", filter)
                .toString();
    }
}

Резюме

Состояние в функциональном реактивном программировании пользовательского интерфейса похоже, но не совпадает с моделью в классическом приложении MVC. Он содержит все состояния, включая состояние пользовательского интерфейса, а не только модель домена. Во многих средах состояние хранится в одной структуре данных, обычно в дереве. Другое ключевое требование — неизменность. Реализация компонента State в Java проста с неизменяемыми POJO.

Следующая часть будет посвящена функции просмотра, которая переводит состояние в фактический пользовательский интерфейс. Если у вас есть какие-либо вопросы, идеи или мысли, пожалуйста, оставьте комментарий. Также не забудьте заценить мой образец JavaFX ReduxFX .

Ссылка: MVC мертв — что будет дальше? — Часть 2 от нашего партнера JCG Майкла Хайнрихса в блоге Майка .