Используется ли ObservableList в JavaFX против разделения Model-View-Controller?

Я пытаюсь изучить JavaFX, потому что я хочу использовать его в качестве графического интерфейса моей программы. Мой вопрос по существу концептуальен:

На сегодняшний день моя программа в основном представляет собой "модельную" часть шаблона MVC; то есть почти весь мой код является OO-представлением абстракций в смысле классов, и весь этот код является логическим кодом.

Поскольку я не хочу быть единственным пользователем моей программы, я хочу добавить часть "Просмотр" MVC, чтобы люди могли легко использовать и манипулировать частью "Модели" моей программы. Для этого я хочу использовать JavaFX.

В моих классах "Model" я, очевидно, использую различные списки, карты и другие классы из API коллекций Java. Чтобы пользователи моей программы могли манипулировать этими базовыми списками и картами, я хочу использовать интерфейсы Observable (List/Map) в JavaFX.

Конкретный пример, обеспечивающий ясность ситуации:

Скажем, что у меня есть класс MachineMonitor, который каждые 3 минуты проверяет определенные свойства машины, например, если соединение все еще хорошо, скорость вращения шестеренок и т.д. Если определенные неравенства выполняются (скажем, что скорость передач снизилась до скорости 1 оборот/с) MachineMonitor запускает RestartMachineEvent.

В настоящее время я использую ArrayList < MachineMonitor > , чтобы отслеживать все индивидуальные MachineMonitor. Теперь, перейдя к части "Просмотр" MVC, я хочу, чтобы Пользователь мог управлять TableView, который отображает список MachineMonitor s, чтобы они могли, например, создавать и удалять новые MachineMonitor для мониторинга различных машин.

Итак, я могу отслеживать, что хочет сделать пользователь моей программы (скажем, создать MachineMonitor для машины № 5, которая проверяет, падает ли оборот/сек передач ниже 0.5) Я использую ObservableList < MachineMonitor > в качестве основного списка для TableView.

Самый простой способ связать "Модель" и "Вид" моей программы - просто изменить класс "Модель", чтобы иметь ObservableList < MachineMonitor > , а не ArrayList < MachineMonitor > но (попадание в тему вопроса) Я чувствую, что это очень грязно, потому что он смешивает код "Model" и "View".

Наивный подход заключается в использовании ObservableList < MachineMonitor > для TableView и сохранения использования моего ArrayList < MachineMonitor > . Однако изменения, внесенные в ObservableList < MachineMonitor > , не влияют на базовый список в соответствии со спецификациями JavaFX.

Учитывая это, лучший способ решить эту загадку, чтобы сделать ChangeListener для ObservableList < MachineMonitor > , который "распространяет" изменения, внесенные в ObservableList < MachineMonitor к базовому "Model" ArrayList < MachineMonitor > ? Возможно, поместите это в класс под названием MachineMonitorController?

Это ad-hoc решение кажется очень грязным и не идеальным.

Мой вопрос: что является лучшим способом сохранить почти полное разделение между "Моделью" и "Вид" в этом сценарии?

Ответ 1

Я не согласен с тем, что использование ObservableList в вашем классе "model" нарушает разделение MVC. ObservableList - чисто представление данных; это часть модели, а не часть представления. я (и другие) использовать свойства и коллекции JavaFX в модели представления во всех уровнях моих приложений. Помимо всего прочего, я указываю, как я использую свойства JavaFX, которые (или могут быть, по крайней мере) связаны с JSF. (Я должен упомянуть, что не все согласны с подходом к использованию свойств FX на стороне сервера, однако я не вижу никакого способа сделать аргумент, что они как-то часть представления.)

Так как JavaFX теперь является полностью полноценной частью стандартной версии Java, вы также не добавляете никаких дополнительных зависимостей. (ObservableList не менее важен для Java SE, чем ArrayList.)

Кроме того, если вы делаете

List<MachineMonitor> myNonObservableList = ... ;

ObservableList<MachineMonitor> myObservableList = FXCollections.observableList(myNonObservableList);
myObservableList.add(new MachineMonitor());

наблюдаемый список поддерживается не наблюдаемым списком, поэтому изменение происходит и в myNonObservableList. Таким образом, вы можете использовать этот подход, если хотите.

Ответ 2

Вкратце, я не думаю, что использование ObservableList нарушает контракт MVC.

Остальное, вы можете читать или нет, как хотите, так как это довольно досадно.

Архитектурный узор фона

Наблюдаемые полезны в архитектуре стиля MVC, потому что они обеспечивают способ подачи данных назад и вперед между компонентами MVC через свободные соединения, где модели и классы классов не используются, t нужно обращаться напрямую друг к другу, но вместо этого может работать с некоторой общей моделью данных, которая передает поток данных. Не случайно, что шаблон Observable и концепция архитектуры MVC возникли примерно одновременно с Xerox PARC - все связано.

Как отмечено в графических интерфейсах Martin Fowler, существует множество различных подходов к созданию графических интерфейсов. MVC - всего лишь один из них, вид дедушки из всех. Приятно хорошо понимать MVC (его часто неправильно понимают), а концепции MVC применимы во многих местах. Для вашего приложения вы должны использовать систему, которая лучше всего подходит для вас, а не жестко следуя заданному шаблону (если вы не используете конкретную структуру, которая применяет данный шаблон), а также открыта для использования разных шаблонов в приложении, а не для того, чтобы пытаться обучать все в единую концептуальную структуру.

Java Beans являются фундаментальной частью почти всех программ Java. Хотя традиционно часто используется только в клиентских приложениях, шаблон наблюдателя через PropertyChangeListeners был, по уважительной причине, частью спецификации Java Bean, поскольку он был создан. Наблюдаемые и обязательные элементы JavaFX - это переработка этой более ранней работы, которая учится у нее для создания чего-то, что удобнее работать и легче понять. Возможно, если бы наблюдаемые и связывающие элементы JavaFX существовали десять или двенадцать лет назад как часть JDK, такие понятия более широко использовались бы в более широком спектре библиотек и фреймворков, чем несколько чистых графических интерфейсов.

Совет

Я предлагаю рассмотреть модель MVVM и другие графические интерфейсы.

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

Я думаю, что правильный выбор архитектуры зависит от вашего приложения, от вашего опыта и от размера и сложности проблем, которые вы пытаетесь решить. Например, если у вас есть распределенная система, вы можете следовать принципам REST, а не (или в дополнение к) MVC. Какой бы вы ни выбрали, архитектура должна помочь вам решить проблему (и, возможно, будущие проблемы), а не наоборот. Более-архивирование решения является общей ловушкой и очень легко сделать, поэтому старайтесь избегать этого.

Caveat

Одно предостережение, которое следует учитывать, заключается в том, что наблюдаемые обязательно работают через побочные эффекты, которые трудно поддаются рассуждению и могут быть противоположными понятию изоляции. В JavaFX есть некоторые хорошие инструменты, такие как ReadOnlyObjectWrapper и ReadOnlyListWrapper, чтобы помочь ограничить воздействие ( если вам нравится) на наблюдаемых, чтобы они не запускались в вашей системе. Используйте такие инструменты (и неизменяемые объекты) с безрассудным отказом.

Изучите примеры

Для простого приложения JavaFX, которое создается с помощью наблюдаемых, см. tic-tac-toe.

Для хорошего способа структурирования большого и сложного приложения JavaFX с компонентами на основе FXML обратитесь к исходному коду SceneBuilder и SceneBuilderKit. Исходный код доступен в JavaFXртурном исходном дереве, просто проверьте его и начать обучение.

Прочитайте на архитектуре управления JavaFX UI. Изучите исходный код управления JavaFX (например, Button и ButtonSkin или ListView и ListViewSkin), чтобы увидеть, как такие концепции, как MVC, могут быть применены с использованием структур JavaFX. Основываясь на этом обучении, попробуйте создать некоторые из собственных пользовательских элементов управления, используя архитектуру, предоставляемую инфраструктурой управления JavaFX. Часто, когда вы создаете собственное приложение, вам не нужно создавать свои собственные элементы управления (по крайней мере, те, которые производят форму JavaFX Control). Архитектура JavaFX Controls специально создана для поддержки встроенных библиотек многоразовых элементов управления, поэтому она не всегда подходит для всех целей; вместо этого он дает конкретную демонстрацию одного проверенного способа добиться определенных целей. Принятие и адаптация проверенных решений долгий путь к тому, чтобы вы не изобретали ненужные вещи и позволяли вам строить прочную основу и учиться на испытаниях других.

Что касается вашего конкретного примера

Советую вам пойти с:

Самый простой способ связать "Модель" и "Вид" моей программы - просто изменить класс "Модель", чтобы иметь ObservableList, а не ArrayList

Возможно, используйте ReadOnlyListWrapper, чтобы вывести ObservableList из MachineMonitor во внешний мир, чтобы ничто не могло его модифицировать неоправданно.

Настройте другую структуру, которая инкапсулирует представление (например, ControlPanel и ControlPanelSkin) и предоставит ему ссылку на только просматриваемый список MachineMonitors. ControlPanelSkin может инкапсулировать TableView, график или любые визуальные кнопки и виджеты, которые вы хотите использовать для пользователя для контроля за машинами.

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

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