Статьи

Декораторы Java EE6: декорирование классов во время внедрения

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

Java EE 6 позволяет нам создавать декораторы через CDI, как часть их функций AOP . Если мы хотим реализовать сквозные задачи , которые все еще достаточно близки к бизнесу, мы можем использовать эту функцию Java EE 6.

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

Интерфейс:

1
2
3
public interface TicketService {
    Ticket orderTicket(String name);
}

Реализация интерфейса создает тикет и сохраняет его.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@Stateless
public class TicketServiceImpl implements TicketService {
  
    @PersistenceContext
    private EntityManager entityManager;
  
    @TransactionAttribute
    @Override
    public Ticket orderTicket(String name) {
        Ticket ticket = new Ticket(name);
        entityManager.persist(ticket);
        return ticket;
    }
}

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
@Decorator
public class TicketServiceDecorator implements TicketService {
  
    @Inject
    @Delegate
    private TicketService ticketService;
    @Inject
    private CateringService cateringService;
  
    @Override
    public Ticket orderTicket(String name) {
        Ticket ticket = ticketService.orderTicket(name);
        cateringService.orderCatering(ticket);
        return ticket;
    }
}

Обратите внимание, что здесь мы применяем 2 аннотации, специфичные для CDI. @Decorator отмечает реализацию как декоратор. У декоратора всегда должен быть делегат, класс, который мы хотим декорировать, помеченный аннотацией @Delegate (в точке внедрения). Также обратите внимание на то, что мы используем интерфейс, а не реализацию.

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

1
@Inject private TicketService ticketService;

Вместо того, чтобы использовать квалификаторы, нам просто нужно отрегулировать наш beans.xml, чтобы пометить TicketServiceDecorator как «Декоратор».

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
    <decorators>
        <class>be.styledideas.blog.decorator.TicketServiceDecorator</class>
    </decorators>
</beans>

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

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

1
2
3
4
<decorators>
    <class>be.styledideas.blog.decorator.HighDecorator</class>
    <class>be.styledideas.blog.decorator.LowDecorator</class>
</decorators>

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

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

Итак, я создал интерфейс:

1
2
3
public interface SocialFeedProcessor {
    Feed process(String feed);
}

и предоставили 2 реализации, твиттер и гугл +

01
02
03
04
05
06
07
08
09
10
public class TwitterFeedProcessor implements SocialFeedProcessor{
  
    @Override
    public Feed process(String feed) {
        System.out.println("processing this twitter feed");
        // processing logics
        return new Feed(feed);
    }
  
}
01
02
03
04
05
06
07
08
09
10
public class GooglePlusFeedProcessor implements SocialFeedProcessor {
  
    @Override
    public Feed process(String feed) {
        System.out.println("processing this google+ feed");
        // processing logics
        return new Feed(feed);
    }
  
}

Я аннотирую эти 2 компонента с помощью специального классификатора, как описано здесь

1
2
3
4
5
6
@javax.inject.Qualifier
@java.lang.annotation.Retention(RUNTIME)
@java.lang.annotation.Target({FIELD, PARAMETER, TYPE})
@java.lang.annotation.Documented
public @interface FeedProcessor {
}

и я аннотирую свои 2 процессора с ним.

01
02
03
04
05
06
07
08
09
10
11
@FeedProcessor
public class TwitterFeedProcessor implements SocialFeedProcessor{
  
    @Override
    public Feed process(String feed) {
        System.out.println("processing this twitter feed");
        // processing logics
        return new Feed(feed);
    }
  
}
01
02
03
04
05
06
07
08
09
10
11
@FeedProcessor
public class GooglePlusFeedProcessor implements SocialFeedProcessor {
  
    @Override
    public Feed process(String feed) {
        System.out.println("processing this google+ feed");
        // processing logics
        return new Feed(feed);
    }
  
}

Ничего особенного, но теперь, когда мы пишем наш декоратор, мы используем мощь CDI, чтобы декорировать классы только с помощью аннотации @FeedProcessor.

01
02
03
04
05
06
07
08
09
10
11
@Decorator
public class SocialFeedDecorator implements SocialFeedProcessor {
    @Delegate
    private @FeedProcessor SocialFeedProcessor processor;
  
    @Override
    public Feed process(String feed) {
        System.out.println("our decorator is decorating");
        return processor.process(feed);
    }
}

осталось только зарегистрировать наш декоратор в файле beans.xml

1
2
3
<decorators>
    <class>be.styledideas.blog.decorator.SocialFeedDecorator</class>
</decorators>

Используя аннотацию, мы автоматически украшаем все наши реализации SocialfeedProcessor этим декоратором. Когда мы добавляем дополнительную реализацию SocialFeedProcessor без аннотации, компонент не будет оформлен.

Справка: декораторы Java EE6, декорирование классов во время внедрения и декораторы Java EE6, расширенное использование от нашего партнера JCG Джелле Виктуор из блога Styled Ideas .

Статьи по Теме :