После того, как я в течение нескольких лет получал удовольствие строить свой код на CDI, вполне естественно использовать его для структурирования моего кода в соответствии с хорошо известными шаблонами. CDI — это механизм внедрения зависимостей, разработанный для использования на серверах приложений Java EE, и это может быть воспринято как недостаток. Однако я хочу показать, что он может использоваться и имеет большой потенциал также в приложении Java SE.
Что хорошо в CDI, так это то, что он представляет собой нечто большее, чем просто инъекционный механизм. Вдобавок к этому он предоставляет также элегантный и мощный механизм передачи событий. Эту функцию можно красиво сочетать с Swing для создания приложения с графическим интерфейсом на основе шаблона MVC.
Действительно возможно эффективно объединить CDI и среду Swing, чтобы быстро и с четкой структурой создать приложение с графическим интерфейсом Java. Оставайтесь с нами, чтобы узнать, как …
Прежде всего, эталонная реализация CDI, называемая Weld, распространяется также в виде отдельной библиотеки. Вы можете добавить его в свой проект и начать его использовать. Единственное отличие от стандартного способа запуска приложения заключается в том, что вам необходимо запустить контейнер Weld, который так же прост, как этот вкладыш:
1
2
3
4
5
|
import org.jboss.weld.environment.se.StartMain; ... public static void main(String[] args) { StartMain.main(args); } |
Чтобы добавить Weld в приложение maven, просто добавьте эту зависимость: org.jboss.weld.se:weld-se:2.2.9.Final . Чтобы выполнить код вашего приложения, вы должны поместить его в метод, который наблюдает событие ContainerInitialized:
1
2
3
|
public void start( @Observes ContainerInitialized startEvent) { // code which would be usually in the main() method } |
В приведенном выше методе вы можете инициализировать свое приложение, построить и отобразить графический интерфейс и дождаться событий Swing.
И тут начинается интересная часть. Я буду использовать механизм событий CDI для реализации связывания между компонентами Swing и моделью, используя шаблон наблюдателя. Идея состоит в том, чтобы запускать пользовательские события всякий раз, когда должно происходить обновление данных, а не изменять данные напрямую. Контроллер наблюдает инициированные события и выполняет действия на основе данных события. Затем действия манипулируют моделью данных и отправляют уведомления для просмотра обновлений данных. Смотрите следующую диаграмму:
Цикл MVC начинается с прослушивателей действий Swing, которые составляют объект действия и генерируют его как событие CDI. Слушатель действия не привязан к какому-либо коду контроллера — контроллер привязан к событию с использованием механизма CDI. Это полностью отделяет код GUI от бизнес-логики. Следующий фрагмент отвечает на событие нажатия кнопки и отправляет действие для добавления значения в счетчик:
1
2
3
4
5
6
7
8
9
|
@ApplicationScoped class MainFrame extends javax.swing.JFrame { @Inject Event<ChangeValueAction> changeValueAction; ... void addButtonActionPerformed(java.awt.event.ActionEvent evt) { changeValueAction.fire(ChangeValueAction.plus(getValue())); } ... } |
Здесь нужно помнить, что наблюдатели событий CDI будут создаваться как новые объекты для любого инициируемого события вместе со всеми зависимостями. Я использовал @ApplicationScoped для MainFrame, чтобы гарантировать, что весь код работает на одном и том же экземпляре.
Здесь нужно упомянуть одну вещь: чтобы CDI работал, экземпляр MainFrame должен быть создан CDI, а не напрямую использовать его конструктор. Это достигается путем внедрения его в уже существующий компонент — например, тот, который наблюдает событие ContainerInitialized, генерируемое при запуске.
Механизм CDI отправляет событие любому методу-наблюдателю, который прослушивает событие этого типа. Мы создаем приложение контроллера и помещаем код в метод наблюдателя, например так:
1
2
3
4
5
6
7
|
public class Application { ... public void updateValueWhenChangeValueAction( @Observes final ChangeValueAction action) { ... // controller action } ... } |
Наконец, контроллер обновляет модель и запускает обновление представления при необходимости. Если мы пойдем дальше, мы можем запустить событие обновления из контроллера, которое будет наблюдаться представлением, в данном случае компонентом MainFrame. Или даже построить модель, которая автоматически запускает события CDI при обновлении. Таким образом, контроллер и представление будут полностью отделены и будут реагировать только на события — события графического интерфейса, передаваемые в направлении от представления к контроллеру, и события обновления данных, передаваемые из контроллера / модели в представление. Таким образом, механизм событий CDI очень удобен для построения Приложение MVC Swing с View отделено от бизнес-логики. Это можно сделать, запустив приложение в контейнере Weld CDI (1 строка кода), запустив действия от слушателей Swing (2 строки кода) и наблюдая за действиями (один метод в любом классе с поддержкой CDI). Действия принимают форму компонента данных, который сам по себе не слишком много строк кода.
- Полный пример можно найти на github: https://github.com/OndrejM/JavaDecoupledUI-CDI
Ссылка: | События CDI в приложении Swing для отделения пользовательского интерфейса и обработки событий от нашего партнера JCG Ондрея Михалого в блоге .Lost in Coding . |