как инициализировать контроллеры javafx с тем же объектом модели?

<p><strong>сценарий</strong></p><p>я создаю графический интерфейс, где несколько видов ссылаются на один и тот же объект модели. </p><p><strong>к чему я привык</strong> </p><p>в swing, если я хочу, чтобы все представления ссылались на одну и ту же модель, я бы передал модель в конструктор. </p><p><strong>чем я сейчас занимаюсь</strong></p><p>в javafx я передаю модель, используя метод установки в представлениях/контроллерах (меню, разделенные панели, вкладки, ...), после загрузки каждого представления/контроллера. я нахожу это очень липким и громоздким. кроме того, я считаю, что это не будет работать, потому что в определенных ситуациях мне нужно, чтобы модель уже существовала в контроллере до инициализации некоторых виджетов контроллера.</p><p><strong>lackluster alternatives</strong></p><p>(примечание: я ссылаюсь на следующие вопросы: </p><ul> <li> <a href="https://stackoverflow.com/questions/10134856/javafx-2-0-how-to-application-getparameters-in-a-controller-java-file/10136403#10136403">javafx 2.0 how-to application.getparameters () в файле controller.java</a> </li> <li> <a href="https://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml/14190310">передача параметров javafx fxml</a> </li> <li> <a href="https://stackoverflow.com/questions/12166786/multiple-fxml-with-controllers-share-object/">несколько fxml с контроллерами, общий объект</a> </li> <li><p> <a href="https://stackoverflow.com/questions/14370183/passing-parameters-to-a-controller-when-loading-an-fxml/14432578#14432578">передача параметров в контроллер при загрузке fxml</a> )</p></li> <li><p>внедрение зависимости</p> <ul> <li>я посмотрел на этом сайте, <a href="http://www.zenjava.com/2011/10/23/javafx-2-0-fxml-and-spring/">http://www.zenjava.com/2011/10/23/javafx-2-0-fxml-and-spring/</a> , и я немного заглянул в google guice , но я не вижу способа упрощенно дать каждому представлению/контроллеру javafx один и тот же объект модели. казалось, что инъекция будет вводить разные модели для каждого вида/контроллера.</li> </ul></li> <li><p>сохранение объекта модели в виде публичной статической переменной</p> <ul> <li>это вариант, но на данный момент мне не нравится идея иметь открытую и доступную публичную статическую модель. очевидно, я могу сделать это частной статической переменной и иметь геттеры и сеттеры, но эта идея мне тоже не очень нравится. </li> </ul></li> <li><p>передача параметров от вызывающего к контроллеру</p> <ul> <li><p>я хочу, чтобы каждый контроллер загружал себя в своем конструкторе, и я хочу, чтобы каждый пользовательский контроллер автоматически вставлялся в его родительский контроллер. например, вкладка обзора карты загружается так:</p> <pre><code>public cardoverviewtab() { fxmlloader fxmlloader = new fxmlloader(getclass().getresource("card\_overview\_tab.fxml")); fxmlloader.setroot(content); fxmlloader.setcontroller(this); try { fxmlloader.load(); } catch (exception e) { e.printstacktrace(); } } </code></pre></li> <li><p>а в контроллере singlegamesetup вкладка обзора карты автоматически вводится в переменную:</p> <pre><code>public class singlegamesetupcontroller extends anchorpane { @fxml private cardoverviewtab cardoverviewtab; // rest of the class } </code></pre></li> <li><p>и часть fxml, содержащая вкладку обзора карты, выглядит следующим образом:</p> <pre><code><cardoverviewtab fx:id="cardoverviewtab" /> </code></pre></li> <li><p>таким образом, мне не нужно беспокоиться о ручной загрузке контроллера, но у меня все еще есть проблема настройки модели.</p></li> </ul></li> <li><p>настройка контроллера на fxmlloader</p> <ul> <li>эта опция похожа на ту, к которой я привык, передавая модель в качестве параметра в конструктор, но у нее все еще есть проблема загрузки контроллеров вручную с помощью fxmlloader. </li> </ul></li> <li><p>event bus</p> <ul> <li>я не слишком много читал об этом, но из того, что я прочитал, шина событий кажется неактивной и устаревшей.</li> </ul></li> <li><p>одиночка</p> <ul> <li>это похоже на общедоступную статическую ссылку на объект модели, которую контроллеры могут получить, но опять же я ищу лучшее решение. плюс, я не хочу модель синглтона.</li> </ul></li> </ul><p><strong>что я ищу</strong></p><p>есть ли способ передать объект модели менее громоздким способом? я ищу способ, который так же прост, как передача модели в конструктор, но я не хочу иметь дело с ручной загрузкой контроллеров через fxmlloader или настройкой модели после загрузки контроллеров. возможно, иметь класс для извлечения модели - это лучший вариант, но я спрашиваю на всякий случай, если есть лучший способ.</p>

<p><strong>обновление</strong></p><p>в дополнение к afterburner.fx, также оформить заказ <a href="http://gluonhq.com/labs/ignite/">gluon ignite</a> :</p><blockquote> <p>gluon ignite позволяет разработчикам использовать популярные структуры внедрения зависимостей в своих приложениях javafx, в том числе внутри своих контроллеров fxml. gluon ignite создает общую абстракцию над несколькими популярными инфраструктурами внедрения зависимостей (в настоящее время guice, spring и dagger, но мы планируем добавить больше, когда потребность станет очевидной). благодаря полной поддержке jsr-330 gluon ignite делает внедрение зависимостей в приложениях javafx тривиальным.</p> </blockquote><p>инжекция объектов модели в контроллеры также осуществляется через @inject, аналогично afterburner.fx.</p><p><strong>предлагаемый подход</strong></p><p>поскольку вы, похоже, ищете среду внедрения зависимостей, я думаю, что ваш лучший вариант - использовать <a href="http://afterburner.adam-bien.com">afterburner.fx framework</a> .</p><p>afterburner.fx предоставляет способ внедрения объектов модели в ваши контроллеры javafx, используя стандартную аннотацию java <a href="http://docs.oracle.com/javaee/6/api/javax/inject/inject.html">@inject</a> . </p><p><strong>альтернативные системы впрыска зависимостей</strong></p><p>spring большой и сложный, и, если вам не нужно много других его функций для вашего приложения, его не следует рассматривать из-за его сложности.</p><p>guice намного проще, чем spring, и является разумным выбором, если вам нужна инфраструктура внедрения зависимостей с многочисленными функциями, такими как классы провайдеров. но, судя по всему, вам не нужны все функции, которые предоставляет guice, поскольку вы просто хотите обойти одноэлементные экземпляры объектов в вашем приложении без явного их поиска.</p><p>итак, попробуйте afterburner.fx и посмотрите, подходит ли он вам.</p><p><strong>afterburner.fx пример кода</strong></p><p>вот пример внедрения экземпляра модели (<code>notesstore</code>) в контроллер с использованием afterburner.fx. образец напрямую скопирован из <a href="http://afterburner.adam-bien.com">afterburner.fx документации</a> .</p><pre><code>import com.airhacks.afterburner.views.fxmlview; public class notelistview extends fxmlview { //usually nothing to do, fxml and css are automatically //loaded and instantiated } public class airpadpresenter implements initializable { @inject // injected by afterburner, zero configuration required notesstore store; @fxml // injected by fxml anchorpane notelist; @override public void initialize(url url, resourcebundle rb) { //view constructed from fxml notelistview notelistview = new notelistview(); //fetching and integrating the view from fxml parent view = notelistview.getview(); this.notelist.getchildren().add(view); } } </code></pre><p> <a href="https://github.com/adambien/followme.fx">followme.fx</a> - это базовый пример приложения, демонстрирующий, как использовать afterburner.fx. у меня было несколько проблем с запуском followme.fx из коробки из-за несовместимости с зависимостями maven, поэтому я <a href="https://github.com/jewelsea/followme.fx">раздвоил его код</a> и исправил некоторые проблемы, которые мешали мне использовать его из коробки.</p><p><strong>ответы на дополнительные вопросы из комментариев</strong></p><blockquote> <p>итак, из примера notestore вы говорите, что все, что мне нужно сделать, это добавить зависимость фреймворка afterburner и поместить @inject в мою переменную модели?</p> </blockquote><p>нет, вам также необходимо создать связанный класс, расширяющий fxmlview, и создать его с помощью нового вызова (аналогично тому, как noteslistview создается в приведенном выше примере кода). если вы заинтересованы в продолжении исследования инфраструктуры afterburner.fx, используйте проект followme.fx в качестве основы, поскольку он предоставляет полный исходный код для очень простого исполняемого примера, использующего эту среду. </p><blockquote> <p>я попробовал google guice и получил его на работу. , , в конструкторе вы увидите, что объект настроек игры вводится вручную.</p> </blockquote><p>я не думаю, что вы должны использовать инжектор guice таким образом. я думаю, что вы можете <a href="http://docs.oracle.com/javafx/2/api/javafx/fxml/fxmlloader.html#setcontrollerfactory%28javafx.util.callback%29">установить фабрику контроллера</a> на экземпляре fxmlloader, чтобы инициировать инъекцию. вот как это делает <a href="https://github.com/adambien/afterburner.fx/blob/master/src/main/java/com/airhacks/afterburner/views/fxmlview.java">fxmlview</a> в afterburner.fx. точная деталь механизма впрыска, используемого в guice, будет отличаться от механизма afterburner.fx, но я думаю, что общая концепция установки фабрики контроллера остается схожей.</p><p>в ответ на: <a href="https://stackoverflow.com/questions/15990777/associating-fxml-and-controller-in-guices-module-configuration">связывание fxml и контроллера в конфигурации модуля guice</a> есть демонстрация фабрики контроллеров набора с использованием fxml и guice.</p><p>обидно, что нет более простого способа сделать это, который не вызывает у вас столько трудностей.</p><p>как несущественное личное замечание, я в некоторой степени амбивалентен в отношении структуры внедрения зависимостей в целом. конечно, они могут помочь, но много раз для простых вещей я часто в порядке с одноэлементным методом getinstance, а не с более сложной структурой. тем не менее, я вижу, как в больших проектах они могут быть полезны, и, безусловно, они очень популярны в определенных средах java.</p>

<p>я исследовал эту проблему и обнаружил, что внедрение зависимостей вместе с синглтоном (для модели) - мой оптимальный дизайн. я узнал, что наличие метода установки для модели в каждом из моих контроллеров является формой внедрения зависимостей, как и передача модели через конструктор. spring и guice являются каркасом, чтобы помочь этому. </p><p>я попытался использовать spring, как указано здесь: <a href="http://www.zenjava.com/2011/10/23/better-controller-injection/">http://www.zenjava.com/2011/10/23/better-controller-injection/</a> , но я столкнулся с проблемой, когда класс конфигурации попытался загрузить контроллер, не удалось загрузить элементы-контроллеры. возможно, это не было проблемой spring, но я подумал, что мне было все равно, чтобы тратить время на то, чтобы все заработало. кроме того, мне пришлось бы просмотреть все файлы контроллера и отредактировать способ их создания.</p><p>обыскав и много прочитав, я обнаружил, что эта статья лучше всего отражает то, что я хотел бы сделать: <a href="https://forums.oracle.com/thread/2301217?tstart=0">https://forums.oracle.com/thread/2301217?tstart=0</a> . поскольку статья ссылается на предлагаемые улучшения, эти улучшения еще не существуют в javafx. но когда они это сделают, я буду их реализовывать. просто для примера, возможность внедрить модель через fxml:</p><pre><code><usevar name="model" type="com.mycom.myapp.modelobject"/> </code></pre>

<p>в datafx framework появился новый api под названием datafx-flow. с этим api вы можете просто внедрить объекты в контроллер представления. кроме того, здесь поддерживаются области применения afterburner.fx. вы можете найти пример здесь: <a href="http://www.guigarage.com/2013/12/datafx-controller-framework-preview/">http://www.guigarage.com/2013/12/datafx-controller-framework-preview/</a> </p>