JVM世界中Flutter的可注射和匕首2之间的比较
#kotlin #android #flutter

我最近一直在玩Flutter。更具体地说,我发现了Injectable;一种用于Google也制造的颤音的依赖注入工具,但与Dagger 2非常相似。由于我在匕首2中也感到很舒服,所以我想在它们之间进行一些比较。

差异

生成的代码

他们拥有的最大区别是,扑响的注射效果是两个库的组合:koude0injectable,其中injectablemakes肯定会生成代码和GetItis,这是编译器内部使用的代码来构建服务位置的;在匕首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>方法,则这些不是普通的飞镖方法,而是从GetItpackage生成构造函数的辅助方法。
要了解Injectable在做什么不同的想法对匕首2生成的KoinKodeIn代码,而不是普通的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)

我很确定,您对每个人的深入研究都会越深,会有更多的差异。让我们看看一些相似之处:

相似之处

我会说InjectableDagger 2是您可以在不同技术堆栈中使用的两个最相似平台。声明是两个平台几乎相同的东西,并且做几乎相同的事情。

声明。

让我们看看您如何在InjectableDagger 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分钟才能习惯这种依赖注入工具,这真是太神奇了。