2016-08-30 2 views
2

Есть ли способ рассказать кинжалу 2, как обеспечить что-то, но не позволить ему впрыскиваться?Может ли зависимость кинжала 2 быть неинъекционной?

Скажем, я хочу ввести Qux. Qux требует Foo и Bar:

@Provides 
@Singleton 
Foo foo() { 
    return new Foo(); 
} 

@Provides 
@Singleton 
Bar bar() { 
    return new Bar(); 
} 

@Provides 
@Singleton 
Qux qux(final Foo foo, final Bar bar) { 
    return new Qux(foo, bar); 
} 

Но что, если я не хочу Foo и Bar быть инъекционный? Возможно, их разоблачение может сломать инкапсуляцию Qux, или, возможно, это какие-то фабрики, для которых я хочу получить доступ только к Qux.

Я думал пару способов, которыми я мог бы достичь этого:

  • Если Foo одноточечно требуется другими поставщиками, я мог бы сделать его членом класса. Но это будет беспорядочно, если Foo имеет несколько собственных зависимостей.
  • Если Bar singleton не нужен никакими другими провайдерами, я мог бы создать экземпляр внутри поставщика Qux. Но это будет беспорядочно, если Qux имеет несколько зависимостей.

Ни одно из этих решений не кажется очень изящным или одаренным. Есть ли другой способ?

ответ

1

Самый простой способ добиться того, что вы пытаетесь сделать, - это определить индивидуальный классификатор пакетов.

package my.pkg; 

@Qualifier 
@Retention(RUNTIME) 
@interface ForMyPackage {} 

Затем, используйте это для привязки для Foo и Bar:

@Provides 
@Singleton 
@ForMyPackage 
Foo foo() { 
    return new Foo(); 
} 

@Provides 
@Singleton 
@ForMyPackage 
Bar bar() { 
    return new Bar(); 
} 

@Provides 
@Singleton 
Qux qux(final @ForMyPackage Foo foo, final @ForMyPackage Bar bar) { 
    return new Qux(foo, bar); 
} 

Таким образом, вы можете только просить, что эти версии Foo и Bar быть введены, если у вас есть доступ к классификатору.

Если все эти привязки находятся в одном модуле, вы даже можете использовать закрытый, вложенный квалификатор в модуле.

Редактируйте спрашивающего:

Я попробовал последнее предложение.

@Qualifier 
@Retention(RUNTIME) 
private @interface NoInject {} 

@Provides 
@Singleton 
@NoInject 
Foo foo() { return new Foo(); } 

Попытка придать Foo вызывает ошибку во время компиляции, как хотелось бы:

Error:(15, 6) Gradle: error: com.mydomain.myapp.Foo cannot be provided without an @Inject constructor or from an @Provides- or @Produces-annotated method. com.mydomain.myapp.MyActivity.foo [injected field of type: com.mydomain.myapp.Foo foo]

Таким образом, хотя сообщение об ошибке немного вводит в заблуждение, этот метод является аккуратным и эффективным.

+0

Да, если привязки для 'Foo' и' Bar' находятся в разных пакетах от привязки для 'Qux', тогда это не сработает, но я бы сказал, что если вы хотите, чтобы эти отношения были немного странными, он пересечет границу пакета. – gk5885

0

Я бы сказал, это звучит так же, как component dependencies.

[..] As an alternative, components can use bindings only from another component interface by declaring a component dependency. When a type is used as a component dependency, each provision method on the dependency is bound as a provider. Note that only the bindings exposed as provision methods are available through component dependencies.

Если вы действительно хотите, чтобы скрыть свой Foo и Bar, вы могли бы сделать модуль, Foo и Bar пакет местных. Затем создайте компонент, который предоставляет только Qux и использует его как зависимость от компонента.

С Foo и Bar являются местными, SubComponent не могут их использовать.
Ваш компонент будет единственным, кто сможет использовать модуль и, таким образом, создать и использовать Foo и Bar в своем графике зависимости.

Смежные вопросы