Яка мотивація за анотацією @ImplementedBy в Guice?


10

Нещодавно я читав про @ImplementedByанотацію, доступну в Google Guice . Це дозволяє програмісту задати прив'язку між інтерфейсом та його реалізацією для подальшого використання в режимі введення залежності. Це приклад щойно вчасно прив’язки .

Я досить звик визначати явні прив’язки в своїх модулях, використовуючи наступний синтаксис:

bind(SomeInterface.class).to(SomeInterfaceImplementation.class);

Згідно з документацією, це еквівалентно наступному використанню @ImplementedByпримітки:

@ImplementedBy(SomeInterfaceImplementation.class)
public interface SomeInterface {
    //method declarations
}

Єдине надбання, яке я бачу тут, - це те, що код незначно коротший. У той же час, цей підхід має право недоліки, зазначені тими ж документами:

Використовуйте @ImplementedByобережно; він додає залежність часу компіляції від інтерфейсу до його реалізації.

Така залежність може не бути проблемою у багатьох випадках, але я особисто бачу це як запах коду.

Які випадки використання @ImplementedByанотації варто використовувати?

Одним із можливих способів, здається, є використання його в коді бібліотеки або рамки. Як описано в документах, анотація може забезпечити прив'язку за замовчуванням, яку легко перекрити явною.

Якщо тип є в обох bind()операторах (як перший аргумент) і має @ImplementedByанотацію, використовується bind()оператор. В анотації пропонується реалізація за замовчуванням, яка може бути замінена прив'язкою.

Таким чином, як розробник бібліотеки, я можу надати своїм користувачам прив'язку поза коробкою, яку можна налаштувати десь у коді клієнта.

Чи є це єдиною причиною існування анотації? Або щось мені не вистачає? Чи можу я отримати що-небудь, використовуючи його в коді, який є лише додатком, який бере на себе певну логіку бізнесу, а не бібліотеку / рамки, які потрібно розширювати?


2
Пов'язане, можливо , повторне
Джефф Боуман

Не суворий дублікат, але тут було цікаве обговорення тут: stackoverflow.com/questions/6197178/…
Річард Водден

Відповіді:


8

Я думаю , що небезпека тут використовується тільки в @ImplementedByанотації. Використовується належним чином, у поєднанні з bind()висловлюваннями у вашому модулі тощо.

Налаштування за замовчуванням чудово підходить для тестування; не обов’язково потрібно чітко визначати макетну ін'єкцію кожного разу, коли ви тестуєте клас, який має багато залежностей, або якщо у вас є клас, від якого залежать багато речей (тому ви повинні визначати макет кожен раз ).

Наприклад, у вас може бути клас:

@ImplementedBy(NoOpDataService.class)
interface DataService {
    Map<String, MyPOJO> getData();
}

А потім NoOpDataService:

class NoOpDataService implements DataService {
    @Override
    public Map<String, MyPOJO> getData() {
        return Collections.emptyMap();
    }
}

Ви ніколи не будете використовувати це у своєму фактичному коді; у своєму модулі Guice ви б прив'язали реалізацію, яка насправді щось робить. Але всі тести на класах, які отримують ін'єкцію, DataServiceбільше не повинні мати макет прив’язки.

tl; dr Я згоден з вами, що наявність інтерфейсів, що залежать від вашої реалізації, може бути запахом коду; але також можна видалити код котла, що спростить тестування. Втілити функцію не важко; і хоча є невеликий потенціал для зловживань, зрештою наслідки не можуть бути занадто поганими (сервіс запускається зненацька), і це було б не надто важко виправити, навіть якщо це трапиться.


3
Додавання тестового коду до виробництва?
Василевс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.