我最近一直在玩Flutter。更具体地说,我发现了Injectable;一种用于Google也制造的颤音的依赖注入工具,但与Dagger 2非常相似。由于我在匕首2中也感到很舒服,所以我想在它们之间进行一些比较。
差异
生成的代码
他们拥有的最大区别是,扑响的注射效果是两个库的组合:koude0和injectable
,其中injectable
makes肯定会生成代码和GetIt
is,这是编译器内部使用的代码来构建服务位置的;在匕首2中,依赖关系是手动生成的。让我们看看一个例子:
@injectable
class ServiceA {}
@injectable
class ServiceB {
ServiceB(ServiceA serviceA);
}
这将生成:
final getIt = GetIt.instance;
void $initGetIt(GetIt getIt) {
final gh = GetItHelper(getIt, environment);
gh.factory<ServiceA>(() => ServiceA());
gh.factory<ServiceB>(ServiceA(getIt<ServiceA>()));
}
如果您检查了factory<T>
方法,则这些不是普通的飞镖方法,而是从GetIt
package生成构造函数的辅助方法。
要了解Injectable
在做什么不同的想法对匕首2生成的Koin
或KodeIn
代码,而不是普通的Java代码(或Kotlin)。
让我们看看匕首将生成两个依赖项,一个通过模块提供了依赖。
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerApplicationComponent implements ApplicationComponent {
private ApplicationModule applicationModule;
private ApplicationModule_ProvideDependency1Factory provideDependency1Factory;
private ApplicationModule_ProvideDependency2Factory provideDependency2Factory;
private Provider<ProvidedDependency> providedDependency;
private DaggerApplicationComponent(Builder builder) {
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
// etc etc etc
....
}
进行DI和现场注射。
这也是两个平台之间的区别。这是由于语言限制或编译器行为。例如,在Flutter/Dart中,如果您继续运行该应用并且不运行:
flutter packages pub run build_runner build
即使您可能在图中添加了新的依赖项,该应用也将继续使用旧的依赖项(这可能会导致崩溃)。
在匕首2中,如果您的依赖项出现问题或在编译过程中出现问题,您将永远知道。当然,在颤音中,您也可以听取依赖性声明的扑声变化,但是匕首2方式似乎更顺利:
flutter packages pub run build_runner watch
现场注射基本上是不同的,因为代码的生成不同:
/// Flutter:
Dependency dependency = getIt<Dependency>();
和匕首2:
// Kotlin
@Inject
lateinit var dependency: Dependency
override fun onInit(){
DaggerSomeComponent.builder().build().inject(this) //or something similar
}
书面代码和编译器/处理器之间的桥梁
好吧,我的意思是入口点。对于匕首2,它的组件是Injectable
,这是一个注释。让我们再次看看一个例子:
final getIt = GetIt.instance;
@InjectableInit(
initializerName: r'$initGetIt',
)
void configureDependencies() => $initGetIt(getIt); // generated after first build
void main() {
configureDependencies();
runApp(MyApp());
}
和匕首2:
@Component(dependencies = [Dep1::class, Dep2::class])
interface MyComponent{
fun dep1() : Dep1
fun dep2() : Dep2
// or for field injection just:
fun inject()
}
DaggerMyComponent.builder().module(WhateverModule()).build().dep1()
// or:
DaggerMyComponent.builder().module(WhateverModule()).build().inject(this)
我很确定,您对每个人的深入研究都会越深,会有更多的差异。让我们看看一些相似之处:
相似之处
我会说Injectable
和Dagger 2
是您可以在不同技术堆栈中使用的两个最相似平台。声明是两个平台几乎相同的东西,并且做几乎相同的事情。
声明。
让我们看看您如何在Injectable
和Dagger 2
中声明依赖项。
@injectable
class ServiceA {}
@injectable
class ServiceB {
ServiceB(ServiceA serviceA);
}
在匕首2中,使用kotlin是:
class ServiceA @Inject constructor()
class ServiceB @Inject constructor(serviceA: ServiceA)
但是如果ServiceA
是单身人士怎么办?
@singleton // or @lazySingleton
class ServiceA {}
和匕首2:
@Singleton
class ServiceA @Inject constructor()
,如果ServiceA
需要建造一个构建器怎么办?为此,我们需要一个模块,正确?
@module
abstract class ServiceModule {
ServiceA serviceA get => ServiceA.builder().someConfiguration().anotherConfiguration().build();
}
@Module
object SomeModule {
@Provides
fun provideServiceA() = ServiceA.builder().someConfiguration().anotherConfiguration().build()
}
在这里很小的差异:在匕首2中,您必须将模块包括在各个组件中,这与可注射的情况不是相同的情况。依赖性将由本身生成。
命名依赖项
由于某些原因,您需要两个相同对象的实例,但要区分它们,则可以始终在这两个工具中使用@Named()
注释:
@injectable
class MyRepo {
final Service service;
MyRepo(@Named('impl1') this.service)
}
class MyRepo @Inject constructor(@Named("impl1") service: ServiceA)
声明中存在差异:
@Named("impl1")
@Injectable(as: Service)
class ServiceImpl implements Service {}
@Named("impl2")
@Injectable(as: Service)
class ServiceImp2 implements Service {}
对于匕首,它可以与一个模块一起使用:
@Module
abstract class SomeModule {
@Provides
@Named("impl1")
abstract fun bindsImpl1Service(serviceImpl: ServiceImpl) : Service
@Provides
@Named("impl2")
abstract fun bindsImpl1Service(serviceImpl: ServiceImp2) : Service
}
工厂模式
这在可注射剂中稍微容易。那是因为它是在匕首之后建造的,即使受到匕首的启发,也可以做得更好,实际上做得更好:
@injectable
class BackendService {
BackendService(@factoryParam String url);
}
在匕首2中,在@AssistedInject
成为图书馆的一部分之前,您需要在Gradle文件中额外依赖。这就是现在的样子:
class BackendService @AssistedInject constructor(private val client: NetworkClient, @Assisted url: String){
@AssistedInject.Factort
interface Factory {
fun create(url: String) : BackendService
}
}
这些功能最能让您想起彼此的功能。不过要注意的一件事是,匕首具有更多功能(和更多的注释),但是由于它们在可注射剂中缺少,要么不是主要功能,所以本文未涵盖该部分。
结束思想
尽管结论哪种工具更好,因为比较的工具在不同的平台上使用了,但我想我仍然是匕首2的老粉丝2在那里,它比以前更简单。但是使用Flutter的注射剂也令人惊讶。我不能说我非常了解整个平台,我花了10分钟才能习惯这种依赖注入工具,这真是太神奇了。