Какова мотивация аннотации @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()оператор. Аннотация предлагает реализацию по умолчанию, которая может быть переопределена привязкой.

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

Является ли это единственной причиной существования аннотации? Или мне чего-то не хватает? Могу ли я получить что-нибудь, используя это в коде, который является просто приложением, заботящимся о некоторой бизнес-логике, а не библиотекой / фреймворком, который нужно расширять?

toniedzwiedz
источник
2
Связанный, возможно, дублирующий вопрос (хотя ваш заголовок понятнее): является ли Guice's @ImplementedBy злым?
Джефф Боуман
Не совсем дубликат, но здесь было несколько интересных обсуждений: 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 больше не нуждаются в фиктивной привязке.

Я согласен с вами, что наличие ваших интерфейсов зависит от вашей реализации, может быть запахом кода; но он также может удалить шаблон кода, чтобы облегчить тестирование. Это не сложно реализовать функцию; и хотя существует небольшой потенциал для злоупотреблений, в конечном итоге последствия не могут быть слишком плохими (служба запускается неожиданно), и это не будет слишком сложно исправить, даже если это произойдет.

durron597
источник
3
Добавление тестового кода в производство?
Базилевс