Рубрики
Без рубрики

Архитектура приложения JavaFX

Введение Я разрабатываю приложения JavaFX уже около 5 лет и использовал разные… С тегами архитектура, java, javafx.

Вступление

Я разрабатываю приложения JavaFX уже около 5 лет и использовал для этого различные шаблоны архитектуры.

Сначала я начал с MVC, затем с MVVM, и, наконец, мы использовали пассивный просмотр MVP в моем текущем проекте.

Способ применения шаблона MVC хорошо описан в документации JavaFX, MVVM хорошо описан в документации фреймворка mvvmFX, но для пассивного представления MVP я потратил много времени на чтение разных статей об этом, но я не нашел способ, который на 100% подходит для меня.

Кроме того, я не нашел удовлетворительной статьи о том, как координировать различные представления, построенные с помощью шаблона MVP.

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

Мое внимание было сосредоточено на:

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

Поэтому я пришел к следующему выводу, который мне нравится.

Структура компонента пользовательского интерфейса

Простой компонент пользовательского интерфейса с несколькими привязками свойств представления

Компонентный Модуль

Весь компонент связан в контексте, который управляет зависимостями. Я использовал guice, поэтому есть частный модуль guice, который управляет внутренними зависимостями.

Более глобальные модули, использующие этот модуль, должны обеспечивать предоставление всех зависимостей, необходимых докладчику.

Ведущий

Основная цель докладчика – предоставить свойства, зависящие от домена, к которым представление может привязываться, и предоставить методы, которым представление может напрямую делегировать.

Это ответственно какая информация отображается, а не как.

Докладчик не должен содержать бизнес-логику, только логику о адаптации между представлением и бизнес-логикой.

Ведущий не знает представления.

public class Presenter { private final StringProperty someString = new SimpleStringProperty(); void doSomething() { // not implemented yet } StringProperty someStringProperty() { return someString; } }
Смотреть

Представление отвечает за то, как отображается информация.

Вид – это скромный объект. Он делает только три вещи:

  • предоставьте пакет – частный заводской метод
  • свяжите свойства элементов управления со свойствами докладчиков и делегируйте действия элементов управления докладчику в методе инициализации
  • предоставьте свой корневой узел общедоступными методами
public class View { @FXML private StackPane root; @FXML private Label label; @FXML private Button button; private final Presenter presenter; private View(Presenter presenter) { this.presenter = presenter; } static View createInstance(Presenter presenter) { View view = new View(presenter); FXMLLoader.load("....", view); return view; } @FXML void initialize(){ label.textProperty().bind(presenter.someStringProperty()); button.setOnAction(event -\> presenter.doSomething()); } public Node getRootNode() { return root; } }

Более сложный компонент пользовательского интерфейса с несколькими привязками свойств представления

Чтобы сохранить презентер в чистоте, мы передаем свойства представления на аутсорсинг в своего рода модель представления.

Viewmodel – это только вспомогательный класс для представления и докладчика, поэтому его уровень доступа должен быть только частным для пакета.

Вложенные компоненты пользовательского интерфейса

Вложите компонент пользовательского интерфейса в качестве дочернего компонента пользовательского интерфейса (вложенность 1:1)

Если вы хотите вложить дочернее представление, вам необходимо установить его модуль в родительский модуль.

Таким образом, вы можете просто ввести открытое представление дочернего компонента в заводской метод родительского представления.

При необходимости его презентатор может напрямую ввести в родителей презентатора.

Вложите компонент как своего рода элемент управления (вложенность 1:n)

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

Было бы решение, чтобы справиться с этим делом таким образом:

  1. ведущий такого “компонента управления” должен быть доступен через само представление, а не через модуль
  2. поставщик модулей представления должен быть введен в родительское представление
  3. родительское представление должно заботиться о создании экземпляров дочерних представлений/элементов управления и распространять их на своего собственного докладчика, который соединяет логику представления

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

Координация компонентов пользовательского интерфейса

У пользователя всегда есть причина для использования интерфейса системы. Таким образом, приложения основаны на вариантах использования.

Реализация этих вариантов использования проецируется в некоторых абстрактных объектах, которые я называю контроллером рабочего процесса.

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

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

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

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

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

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

Но, на мой взгляд, интерфейс более ориентирован на объект, и гораздо сложнее поддерживать модель чистой и независимой от рабочего процесса и материалов докладчика, чем интерфейс.

Таким образом, ведущий сверху мог выглядеть так:

public class Presenter implements WorkflowTask{ private final StringProperty someString = new SimpleStringProperty(); private Consumer\ onDoSomething; @Override public void showSomeString(String string) { someString.set(string); } @Override public void setOnDoSomething(Consumer\ onDoSomething) { this.onDoSomething = onDoSomething; } void doSomething() { onDoSomething.accept(someString.get()); } StringProperty someStringProperty() { return someString; } }

Взаимодействие с серверной частью

Контроллеры рабочих процессов обрабатывают взаимодействие с серверной частью.

По соображениям тестируемости я предпочитаю использовать класс обслуживания, который внутренне делегирует услугу fx и возвращает завершенное будущее своим клиентам.

Если вас интересуют Angular и AWS, прочитайте мою статью о как перенести angular spa в облако

.

Сообщение Архитектура приложения JavaFX появилось впервые на маймаркт .

Оригинал: “https://dev.to/_maimart_/architecture-of-a-javafx-application-2geb”