Изучаем Java EE 7 - [18]

Шрифт
Интервал


Рис. 2.3. Схема класса с интерфейсом NumberGenerator и реализациями


Как бы вы соединили BookService с ISBN-реализацией интерфейса NumberGenerator? Одно из решений — использовать старое доброе ключевое слово new, как показано в листинге 2.2.


Листинг 2.2. POJO-объект BookService, создающий зависимости с использованием ключевого слова new

>public class BookService {

>··private NumberGenerator numberGenerator;

>··public BookService() {

>····this.numberGenerator = new IsbnGenerator();

>··}

>··public Book createBook(String title, Float price, String description) {

>····Book book = new Book(title, price, description);

>····book.setIsbn(numberGenerator.generateNumber());

>····return book;

>··}

>}

Код в листинге 2.2 достаточно прост и выполняет необходимые действия. BookService создает в конструкторе экземпляр IsbnGenerator, который затем влияет на атрибут numberGenerator. Вызов метода numberGenerator.generateNumber() сгенерирует номер из 13 цифр.

Но что, если вы хотите выбирать между реализациями, а не просто привязываться к IsbnGenerator? Одно из решений — передать реализацию конструктору и предоставить внешнему классу возможность выбирать, какую реализацию использовать (листинг 2.3).


Листинг 2.3. Объект POJO BookService, выбирающий зависимости с использованием конструктора

>public class BookService {

>··private NumberGenerator numberGenerator;

>··public BookService(NumberGenerator numberGenerator) {

>····this.numberGenerator = numberGenerator;

>··}

>··public Book createBook(String title, Float price, String description) {

>····Book book = new Book(title, price, description);

>····book.setIsbn(numberGenerator.generateNumber());

>····return book;

>··}

>}

Таким образом, внешний класс смог использовать BookService с необходимой реализацией.

>BookService bookService = new BookService(new IsbnGenerator())

>BookService bookService = new BookService(new IssnGenerator())

Этот пример иллюстрирует инверсию управления: инвертируется управление созданием зависимости (а не сам класс) между BookService и NumberGenerator, так как оно дается внешнему классу. Поскольку в конце вы соединяете зависимости самостоятельно, эта техника называется конструированием вручную. В предыдущем примере кода мы использовали конструктор для выбора реализации (внедрение конструктора), но еще один привычный способ состоит в использовании сеттеров (внедрение сеттера). Однако вместо конструирования зависимостей вручную вы можете перепоручить эту задачу механизму внедрения (например, CDI).


@Inject

Поскольку Java EE является управляемой средой, вам не придется конструировать зависимости вручную. Вместо вас ссылку может внедрить контейнер. Одним словом, внедрение зависимостей CDI — это возможность внедрять одни компоненты в другие с сохранением безопасности типов, что означает использование XML вместо аннотаций.

Внедрение уже существовало в Java EE 5 с такими аннотациями, как @Resource, @PersistentUnit и EJB. Но оно было ограничено до определенных ресурсов (баз данных, архитектура EJB) и компонентов (сервлетов, компонентов EJB, связующих компонентов JSF и т. д.). С помощью CDI вы можете внедрить практически что угодно и куда угодно благодаря аннотации @Inject. Обратите внимание, что в Java EE 7 разрешено использовать другие механизмы внедрения (@Resource), однако лучше стараться применять @Inject везде, где это возможно (см. подраздел «Производители данных» раздела «Создание компонента CDI» этой главы).

Листинг 2.4 показывает, как внедрять в BookService ссылку на NumberGenerator с помощью объекта CDI.


Листинг 2.4. BookService, использующий @Inject для получения ссылки на NumberGenerator

>public class BookService {

>··@Inject

>··private NumberGenerator numberGenerator;

>··public Book createBook(String title, Float price, String description) {

>····Book book = new Book(title, price, description);

>····book.setIsbn(numberGenerator.generateNumber());

>····return book;

>··}

>}

Как видно из листинга 2.4, простая аннотация @Inject у атрибута сообщит контейнеру, что ему необходимо внедрить ссылку на реализацию NumberGenerator, относящуюся к свойству NumberGenerator. Это называется точкой внедрения (место, где находится аннотация @Inject). Листинг 2.5 показывает реализацию IsbnGenerator. Как видите, здесь нет специальных аннотаций, а класс реализует интерфейс NumberGenerator.


Листинг 2.5. Компонент IsbnGenerator

>public class IsbnGenerator implements NumberGenerator {

>··public String generateNumber() {

>····return "13-84356-" + Math.abs(new Random(). nextInt());

>··}

>}


Точки внедрения

Во время инстанцирования компонента происходит внедрение в той точке, которая указана в аннотации @Inject. Внедрение может происходить с помощью трех различных механизмов: свойства, сеттера или конструктора.

Во всех предыдущих примерах кода вы видели аннотацию @Inject к атрибутам (свойствам):

>@Inject

>private NumberGenerator numberGenerator;

Обратите внимание, что не обязательно создавать метод геттера и сеттера для атрибута, чтобы использовать внедрение. CDI может получить прямой доступ к полю с внедренным кодом (даже если оно приватное), что иногда помогает исключить лишний код. Но вместо аннотирования атрибутов вы можете добавить аннотацию @Inject к конструктору, как показано ниже:


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.