Отборочные соревнования на CDI


ВВЕДЕНИЕ

Давайте начнем говорить немного о квалификаторах CDI, как многие могут знать, CDI — это спецификация JAVA, которая дала много возможностей и расширений языку, я не буду вдаваться в достоинства разговора о спецификации, только о функциональности квалификаторов.

КЛАССИФИКАТОРЫ ИЛИ КЛАССИФИКАТОР

Представьте, что у нас есть интерфейс с несколькими реализациями, одна из функций классификатора — сообщить, какую реализацию мы будем использовать, посмотрите на пример.

public interface PaymentMethod {
    public void pay();
}
Войдите в полноэкранный режим Выход из полноэкранного режима

тогда у нас есть две реализации для интерфейса PaymentMethod

public class CreditCard implements PaymentMethod {
    @Override
    public void pay() {
        System.out.println("payment by cred card");
    }
}
Войдите в полноэкранный режим Выход из полноэкранного режима
public class Cash implements PaymentMethod {

    @Override
    public void pay() {
        System.out.println("payment by CASH");
    }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Если в нашем клиентском классе мы просто инжектируем интерфейс PaymentMethod, CDI выдаст исключение неоднозначности, говоря, что он не знает, какую реализацию инжектировать.

public class Checkout {

    @Inject
    private PaymentMethod payment;

    public void checkout() {
        payment.pay();
    }

}
Войдите в полноэкранный режим Выход из полноэкранного режима

Проверьте ошибку, которая появится на вашей консоли.

WELD-001475: The following beans match by type, but none have matching qualifiers:
- Managed Bean [class br.com.cassunde.cdi.qualifier.Cash] with qualifiers [@Any @Payment],
- Managed Bean [class br.com.cassunde.cdi.qualifier.CreditCard] with qualifiers [@Any @Payment]
Войдите в полноэкранный режим Выход из полноэкранного режима

Чтобы решить эту проблему, мы должны создать классификатор CDI, его создание довольно просто, достаточно создать стандартную аннотацию java с небольшим отличием, эта наша аннотация будет иметь @Qualifier, как следует из названия, будет отвечать за указание того, что наша аннотация и классификатор.

@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
@Qualifier
public @interface PaymentCreditCard {}
Войдите в полноэкранный режим Выход из полноэкранного режима

Давайте сделаем плохой пример, а затем посмотрим лучший способ решения этой проблемы с помощью классификатора. В нашем примере интерфейс PaymentMethod имеет две реализации, CreditCard и Cash, в нашем плохом подходе мы сделаем еще одну аннотацию для квалификации второй реализации, так что давайте перейдем туда: Квалификатор для реализации наличных:

@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
@Qualifier
public @interface PaymentCash {}
Войдите в полноэкранный режим Выход из полноэкранного режима

чтобы использовать эти классификаторы, это будет выглядеть примерно так — Реализация кредитных карт

@PaymentCreditCard
public class CreditCard implements PaymentMethod {

    @Override
    public void pay() {
        System.out.println("payment by creditcard");
    }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Клиентский класс

public class Checkout {

    @Inject
    @PaymentCreditCard
    private PaymentMethod payment;

    public void checkout() {
        System.out.println("Starting checkout");
        payment.pay();
    }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Такой способ не очень хорош, если появится новая реализация, нам придется создавать новую аннотацию и так далее… Давайте теперь улучшим этот подход, вставим перечисление в наш классификатор.

Я создам это перечисление и третий классификатор под названием Payment

public enum PaymentType {
    CREDIT,
    CASH,
    DEBIT
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Наш третий классификатор будет выглядеть следующим образом

@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
@Qualifier
public @interface Payment {
    PaymentType type();
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Теперь мы можем заменить первый созданный нами классификатор на этот, выглядящий примерно так

Реализация кредитных карт

@Payment(type=PaymentType.CREDIT)
public class CreditCard implements PaymentMethod {

    @Override
    public void pay() {
        System.out.println("payment by cred card");
    }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Метод клиента

public class Checkout { 

    @Inject
    @Payment(type=PaymentType.CREDIT)
    private PaymentMethod payment; 

    public void checkout() {
        System.out.println("Starting checkout");
        payment.pay();
    }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Реализация денежных средств

@Payment(type=PaymentType.CASH)
public class Cash implements PaymentMethod {

    @Override
    public void pay() {
        System.out.println("payment by cred card");
    }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Клиентский метод

public class Checkout { 

    @Inject
    @Payment(type=PaymentType.CASH)
    private PaymentMethod payment; 

    public void checkout() {
        System.out.println("Starting checkout");
        payment.pay();
    }
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Обратите внимание, что теперь мы используем только одну аннотацию и «печатаем» наш классификатор, таким образом, у нас больше свободы для развития кода.

На этом пока все.

Оцените статью
devanswers.ru
Добавить комментарий