Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Injeção de Dependência - Uma visão estrutural

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

Injeção de Dependência - Uma visão estrutural

Visualizando na prática as condições e componentes que nos auxiliam a ter uma estrutura de injeção de dependência sólida e robusta, fazendo uma avaliação de problemas comuns em desenvolvimento android.

Avatar for Gabriel Freitas Vasconelos

Gabriel Freitas Vasconelos

August 07, 2019

Other Decks in Programming

Transcript

  1. Tá bom, já vi isso… class MyClass { fun calculate(expr:

    Expr): Expr { val calc = Calculator() return calc.eval(expr) } }
  2. Tá bom, já vi isso… class MyClass {
 fun calculate(expr:

    Expr): Expr {
 
 return calc.eval(expr)
 }
 } class MyClass( ) {
 fun calculate(expr: Expr): Expr {
 
 return calc.eval(expr)
 }
 } val calc = Calculator() val calc: Calculator
  3. Tá bom, já vi isso… class MyClass {
 fun calculate(expr:

    Expr): Expr {
 
 return calc.eval(expr)
 }
 } class MyClass( ) {
 fun calculate(expr: Expr): Expr {
 
 return calc.eval(expr)
 }
 } val calc = Calculator() val calc: Calculator
  4. Tá bom, já vi isso… class MyClass {
 fun calculate(expr:

    Expr): Expr {
 
 return calc.eval(expr)
 }
 } class MyClass( ) {
 fun calculate(expr: Expr): Expr {
 
 return calc.eval(expr)
 }
 } val calc = Calculator() val calc: Calculator
  5. Tá bom, já vi isso… class MyClass {
 fun calculate(expr:

    Expr): Expr {
 
 return calc.eval(expr)
 }
 } class MyClass( ) {
 fun calculate(expr: Expr): Expr {
 
 return calc.eval(expr)
 }
 } val calc = Calculator() val calc: Calculator
  6. Tá bom, já vi isso… fun calculate(expr: Expr): Expr class

    MyClass(val calc: Calculator) { {
 
 return calc.eval(expr)
 }
 }
  7. Tá bom, já vi isso… fun calculate(expr: Expr): Expr class

    MyClass(val calc: Calculator) { =
 calc.eval(expr)
 }
  8. Mas e o conceito? Injeção de dependência é o mais

    vantajoso tipo de Inversão de Controle
  9. Mas e o conceito? Injeção de dependência é o mais

    vantajoso tipo de Inversão de Controle É um dos princípios SOLID
  10. Mas e o conceito? Injeção de dependência é o mais

    vantajoso tipo de Inversão de Controle É um dos princípios SOLID
  11. Como fazer isso funcionar? fun calculate(expr: Expr): Expr =
 calc.eval(expr)


    } class MyClass( val calc: Calculator = Calculator() ) {
  12. Podemos torna-lo Singleton fun eval(expr: Expr): Expr { … }

    } private constructor() class Calculator {
  13. Podemos torna-lo Singleton fun eval(expr: Expr): Expr { … }

    } private constructor() class Calculator { companion object { private var INSTANCE: Calculator? = null fun getInstance() = INSTANCE ?: Calculator().also { INSTANCE = it } }
  14. Mas e se a gente dependesse de… class MyView( @StyleRes

    val currentTheme: Int, ) : MyContract.View { lateinit var presenter: MyContract.Presenter // … }
  15. Mas e se a gente dependesse de… class MyView( @StyleRes

    val currentTheme: Int, ) : MyContract.View { lateinit var presenter: MyContract.Presenter // … } Dependemos de um tipo nativo E de uma Interface Que precisa ser injetada a posteriori
  16. Há casos não cobertos E se nossa dependência for em

    uma abstração? interface ChessPlayer class RookieChessPlayer : ChessPlayer class GMChessPlayer : ChessPlayer
  17. Há casos não cobertos E se nossa dependência for em

    uma abstração? interface ChessPlayer class RookieChessPlayer : ChessPlayer class GMChessPlayer : ChessPlayer E se nossa dependência for em uma classe que não possuímos
 ou em um tipo primitivo? interface GithubApi // Gerado pelo Retrofit val targetCluster: String // Tipo primitivo
  18. Há casos não cobertos E se nossa dependência for em

    uma abstração? interface ChessPlayer class RookieChessPlayer : ChessPlayer class GMChessPlayer : ChessPlayer E se nossa dependência for em uma classe que não possuímos
 ou em um tipo primitivo? interface GithubApi // Gerado pelo Retrofit val targetCluster: String // Tipo primitivo E se o consumidor da nossa classe não for nosso? class MessageWorker : Worker // Usado por WorkManager class HomeViewModel : ViewModel // Mantido via provider
  19. Há casos não cobertos E se precisarmos de mais de

    uma instância? val featuraAEnabled: Boolean val featureBEnabled: Boolean
  20. Há casos não cobertos E se precisarmos de mais de

    uma instância? val featuraAEnabled: Boolean val featureBEnabled: Boolean E se quisermos ter mais controle sobre o ciclo de vida das
 instâncias de nossas dependências? Referências reutilizáveis e fracas, ou fortes em escopo específico
  21. Há casos não cobertos E se precisarmos de mais de

    uma instância? val featuraAEnabled: Boolean val featureBEnabled: Boolean E se quisermos ter mais controle sobre o ciclo de vida das
 instâncias de nossas dependências? Referências reutilizáveis e fracas, ou fortes em escopo específico Resolução de dependência após construção
  22. Há casos não cobertos E se precisarmos de mais de

    uma instância? val featuraAEnabled: Boolean val featureBEnabled: Boolean E se quisermos ter mais controle sobre o ciclo de vida das
 instâncias de nossas dependências? Referências reutilizáveis e fracas, ou fortes em escopo específico Resolução de dependência após construção E como lidaríamos com tipos genéricos? val versions: List<Int> val children: List<Node>
  23. Vamos dar um passo para trás E se tivéssemos alguém

    pra gerenciar essas instâncias para nós?
  24. Vamos dar um passo para trás E se tivéssemos alguém

    pra gerenciar essas instâncias para nós? class HomeViewModel interface BackendApi class MessagingManager class ServiceProvider : Provider val featureAEnabled: Boolean class ConfigFactory<T>
  25. Vamos dar um passo para trás E se tivéssemos alguém

    pra gerenciar essas instâncias para nós? class HomeViewModel interface BackendApi class MessagingManager val featureAEnabled: Boolean class ConfigFactory<T> class ServiceProvider : Provider
  26. Vamos dar um passo para trás E se tivéssemos alguém

    pra gerenciar essas instâncias para nós?
  27. Vamos dar um passo para trás E se tivéssemos alguém

    pra gerenciar essas instâncias para nós? a. É capaz de prover instância para todo
 objeto que possa ser referenciado no
 código, ou para seus providers*
  28. Vamos dar um passo para trás E se tivéssemos alguém

    pra gerenciar essas instâncias para nós? a. É capaz de prover instância para todo
 objeto que possa ser referenciado no
 código, ou para seus providers* *Mais sobre isto adiante
  29. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder() .baseUrl(“https:$//chess.com/”) .client(okHttpClient) .build()
  30. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder() .baseUrl(“https:$//chess.com/”) .client(okHttpClient) .build() val boardPrinter: BoardPrinter = GLCompletePrinter() val debugPrinter: BoardPrinter = MinimalPrinter() val availablePrinters: Map<String, BoardPrinter> = mapOf( “DEFAULT” to boardPrinter, “DEBUG” to debugPrinter )
  31. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder() .baseUrl(“https:$//chess.com/”) .client(okHttpClient) .build() val boardPrinter: BoardPrinter = GLCompletePrinter() val debugPrinter: BoardPrinter = MinimalPrinter() val availablePrinters: Map<String, BoardPrinter> = mapOf( “DEFAULT” to boardPrinter, “DEBUG” to debugPrinter ) val versionName: String = “BLUE-Kasparov”
  32. Vamos dar um passo para trás E se tivéssemos alguém

    pra gerenciar essas instâncias para nós? a. É capaz de prover instância para todo
 objeto que possa ser referenciado no
 código, ou para seus providers* b. É capaz de controlar o ciclo de vida de
 suas referências* *Mais sobre isto adiante
  33. Vamos dar um passo para trás E se tivéssemos alguém

    pra gerenciar essas instâncias para nós? a. É capaz de prover instância para todo
 objeto que possa ser referenciado no
 código, ou para seus providers* b. É capaz de controlar o ciclo de vida de
 suas referências* *Mais sobre isto adiante
  34. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder()
 .baseUrl(“https:$//chess.com/”) 
 .client(okHttpClient)
 .build()
  35. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder()
 .baseUrl(“https:$//chess.com/”) 
 .client(okHttpClient)
 .build() val gameSession get() = GameSession( retrofit, boardPrinter
 )
  36. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder()
 .baseUrl(“https:$//chess.com/”) 
 .client(okHttpClient)
 .build() val gameSession get() = GameSession( retrofit, boardPrinter
 ) object Injector { }
  37. Vamos dar um passo para trás fun eval(expr: Expr): Expr

    { … } } private constructor() class Calculator { companion object {
 private var INSTANCE: Calculator? = null
 fun getInstance() = INSTANCE $?: Calculator().also { INSTANCE = it }
 }
  38. Vamos dar um passo para trás fun eval(expr: Expr): Expr

    { … } } class Calculator { BOILERPLATE! private constructor() companion object {
 private var INSTANCE: Calculator? = null
 fun getInstance() = INSTANCE $?: Calculator().also { INSTANCE = it }
 }
  39. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder()
 .baseUrl(“https:$//chess.com/”) 
 .client(okHttpClient)
 .build() val gameSession get() = GameSession( retrofit, boardPrinter
 ) object Injector { }
  40. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder()
 .baseUrl(“https:$//chess.com/”) 
 .client(okHttpClient)
 .build() val gameSession get() = GameSession( retrofit, boardPrinter
 ) object Injector { val calculator by lazy { Calculator() } }
  41. Vamos dar um passo para trás fun calculate(expr: Expr): Expr

    =
 calc.eval(expr)
 } class MyClass( val calc: Calculator ) { = Calculator()
  42. Vamos dar um passo para trás fun calculate(expr: Expr): Expr

    =
 calc.eval(expr)
 } class MyClass( val calc: Calculator ) { = Calculator() BOILERPLATE!
  43. Vamos dar um passo para trás fun calculate(expr: Expr): Expr

    =
 calc.eval(expr)
 } class MyClass(val calc: Calculator) {
  44. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder()
 .baseUrl(“https:$//chess.com/”) 
 .client(okHttpClient)
 .build() val gameSession get() = GameSession( retrofit, boardPrinter
 ) object Injector { val calculator by lazy { Calculator() } }
  45. Vamos dar um passo para trás val okHttpClient = OkHttpClient.Builder().build()

    val retrofit = Retrofit.Builder()
 .baseUrl(“https:$//chess.com/”) 
 .client(okHttpClient)
 .build() val gameSession get() = GameSession( retrofit, boardPrinter
 ) object Injector { val calculator by lazy { Calculator() } } val myClass get() = MyClass(calculator)
  46. E como seria em uma Activity? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } }
  47. E como seria em uma Activity? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } <- Service Locator
  48. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } }
  49. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel = Injector.mainViewModel
  50. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel = Injector.mainViewModel ???
  51. E como seria com uma ViewModel? Rapidamente, como funciona uma

    ViewModel AAC Activity ViewModelStore ViewModel
  52. E como seria com uma ViewModel? Rapidamente, como funciona uma

    ViewModel AAC Activity ViewModelStore ViewModel ViewModelProvider Provê instância
  53. E como seria com uma ViewModel? Rapidamente, como funciona uma

    ViewModel AAC Activity ViewModelStore ViewModel ViewModelProvider Guarda instância Provê instância
  54. E como seria com uma ViewModel? Rapidamente, como funciona uma

    ViewModel AAC Activity ViewModelStore ViewModel Factory ViewModelProvider Criado por Cria instância Guarda instância Provê instância
  55. E como seria com uma ViewModel? Rapidamente, como funciona uma

    ViewModel AAC Activity ViewModelStore ViewModel Factory ViewModelProvider Criado por Cria instância Guarda instância Provê instância Esta estrutura permite que uma ViewModel sobreviva a
 mudanças de configuração
  56. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel = Injector.mainViewModel
  57. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel by lazy { ViewModelProvider(viewModelStore, viewModelFactory) .get(MainViewModel ::class.java) }
  58. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel by lazy { ViewModelProvider(viewModelStore, viewModelFactory) .get(MainViewModel ::class.java) } viewModelFactory De onde vem??
  59. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } }
  60. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } class MainViewModelFactory : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { return MainViewModel(homeUseCase) as T } }
  61. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } class MainViewModelFactory : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { return MainViewModel(homeUseCase) as T } } homeUseCase
  62. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } override fun <T : ViewModel?> create(modelClass: Class<T>): T { return MainViewModel(homeUseCase) as T } } : ViewModelProvider.Factory { class MainViewModelFactory
  63. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } override fun <T : ViewModel?> create(modelClass: Class<T>): T { return MainViewModel(homeUseCase) as T } } : ViewModelProvider.Factory { ( private val homeUseCase: HomeUseCase ) class MainViewModelFactory
  64. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } override fun <T : ViewModel?> create(modelClass: Class<T>): T { return MainViewModel(homeUseCase) as T } } : ViewModelProvider.Factory { ( private val homeUseCase: HomeUseCase ) class MainViewModelFactory Isso não escala bem
  65. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, ViewModel>
  66. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, ViewModel> = mapOf( MainViewModel ::class.java to MainViewModel(homeUseCase) )
  67. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } override fun <T : ViewModel?> create(modelClass: Class<T>): T { } } ) : ViewModelProvider.Factory { class MainViewModelFactory( private val homeUseCase: HomeUseCase return MainViewModel(homeUseCase) as T
  68. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } override fun <T : ViewModel?> create(modelClass: Class<T>): T { } } ) : ViewModelProvider.Factory { class MainViewModelFactory( val viewModelMap: Map<Class<out ViewModel>, ViewModel> return MainViewModel(homeUseCase) as T
  69. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } override fun <T : ViewModel?> create(modelClass: Class<T>): T { } } ) : ViewModelProvider.Factory { class MainViewModelFactory( val viewModelMap: Map<Class<out ViewModel>, ViewModel> return viewModelMap[modelClass] as T
  70. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } override fun <T : ViewModel?> create(modelClass: Class<T>): T { } } ) : ViewModelProvider.Factory { class MainViewModelFactory( val viewModelMap: Map<Class<out ViewModel>, ViewModel> return viewModelMap[modelClass] as T Mas peraê… ainda há um problema aqui!
  71. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, ViewModel> = mapOf( MainViewModel$::class.java to MainViewModel(homeUseCase)
 )
  72. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, ViewModel> = mapOf( MainViewModel$::class.java to MainViewModel(homeUseCase)
 ) ViewModel
  73. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, ViewModel> = mapOf( MainViewModel$::class.java to MainViewModel(homeUseCase)
 ) ViewModel Precisamos de uma… factory
  74. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, ViewModel> = mapOf( MainViewModel$::class.java to 
 ) MainViewModel(homeUseCase)
  75. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, > = () -> ViewModel mapOf( MainViewModel$::class.java to 
 ) MainViewModel(homeUseCase)
  76. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, > = () -> ViewModel mapOf( MainViewModel$::class.java to 
 ) { MainViewModel(homeUseCase) }
  77. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } ) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { return viewModelMap[modelClass] } } class MainViewModelFactory( val viewModelMap: Map<Class<out ViewModel>, as T ViewModel>
  78. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } ) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { return viewModelMap[modelClass] } } class MainViewModelFactory( val viewModelMap: Map<Class<out ViewModel>, as T () -> ViewModel>
  79. E como seria com uma ViewModel? class MainViewModel( private val

    homeUseCase: HomeUseCase ) : ViewModel() { fun foo(): LiveData<Bar> { … } } ) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { return viewModelMap[modelClass] } } class MainViewModelFactory( val viewModelMap: Map<Class<out ViewModel>, as T () () -> ViewModel>
  80. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, > = () $-> ViewModel mapOf( MainViewModel$::class.java to 
 ) { MainViewModel(homeUseCase) }
  81. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, > = () $-> ViewModel mapOf( MainViewModel$::class.java to 
 ) { MainViewModel(homeUseCase) } val viewModelFactory = ViewModelFactory(viewModels)
  82. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel by lazy { ViewModelProvider(viewModelStore, viewModelFactory) .get(MainViewModel$::class.java) }
  83. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel by lazy { ViewModelProvider(viewModelStore, viewModelFactory) .get(MainViewModel$::class.java) } Injector.
  84. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, > = () $-> ViewModel mapOf( MainViewModel$::class.java to 
 ) { MainViewModel(homeUseCase) } val viewModelFactory = ViewModelFactory(viewModels)
  85. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, > = () $-> ViewModel mapOf( MainViewModel$::class.java to 
 ) { MainViewModel(homeUseCase) } val viewModelFactory = ViewModelFactory(viewModels) fun viewModelProvider(storeOwner: ViewModelStoreOwner) = ViewModelProvider( storeOwner.viewModelStore, viewModelFactory )
  86. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel by lazy { ViewModelProvider(viewModelStore, viewModelFactory) .get(MainViewModel ::class.java) }
  87. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel by lazy { ViewModelProvider(viewModelStore, viewModelFactory) .get(MainViewModel ::class.java) } inline fun <reified T : ViewModel> ViewModelStoreOwner .getViewModel() = Injector .viewModelProvider(this) .get(T ::class.java)
  88. E como seria com uma ViewModel? class MainActivity : AppCompatActivity()

    { val myClass = Injector.myClass override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel by lazy { } getViewModel<MainViewModel>() inline fun <reified T : ViewModel> ViewModelStoreOwner .getViewModel() = Injector .viewModelProvider(this) .get(T ::class.java)
  89. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, > = () $-> ViewModel mapOf( MainViewModel$::class.java to 
 ) { MainViewModel(homeUseCase) } val viewModelFactory = ViewModelFactory(viewModels) fun viewModelProvider(storeOwner: ViewModelStoreOwner) = ViewModelProvider( storeOwner.viewModelStore, viewModelFactory )
  90. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels: Map<Class<out ViewModel>, > = () $-> ViewModel mapOf( MainViewModel$::class.java to 
 ) { MainViewModel(homeUseCase) } val viewModelFactory = ViewModelFactory(viewModels) fun viewModelProvider(storeOwner: ViewModelStoreOwner) = ViewModelProvider( storeOwner.viewModelStore, viewModelFactory ) Isso com certeza vai ficar gigantesco…
  91. E como seria com uma ViewModel? val homeUseCase get() =

    HomeUseCase() object Injector { } val viewModels > = () $-> ViewModel mapOf( MainViewModel$::class.java to 
 ) { MainViewModel(homeUseCase) } val viewModelFactory = ViewModelFactory(viewModels) fun viewModelProvider(storeOwner: ViewModelStoreOwner) = ViewModelProvider( storeOwner.viewModelStore, viewModelFactory ) : Map<Class<out ViewModel>,
  92. Vamos dar outro passo para trás Já temos alguém pra

    gerenciar essas instâncias para nós, mas 
 que temos que separar o gerenciamento da declaração. class HomeViewModel interface BackendApi class MessagingManager class ServiceProvider : Provider val featureAEnabled: Boolean class ConfigFactory<T>
  93. Vamos dar outro passo para trás Já temos alguém pra

    gerenciar essas instâncias para nós, mas 
 que temos que separar o gerenciamento da declaração. class HomeViewModel interface BackendApi class MessagingManager class ServiceProvider : Provider val featureAEnabled: Boolean class ConfigFactory<T>
  94. Vamos dar outro passo para trás Já temos alguém pra

    gerenciar essas instâncias para nós, mas 
 que temos que separar o gerenciamento da declaração. class HomeViewModel interface BackendApi class MessagingManager class ServiceProvider : Provider val featureAEnabled: Boolean class ConfigFactory<T>
  95. Vamos dar outro passo para trás Já temos alguém pra

    gerenciar essas instâncias para nós, mas 
 que temos que separar o gerenciamento da declaração. class HomeViewModel interface BackendApi class MessagingManager class ServiceProvider : Provider val featureAEnabled: Boolean class ConfigFactory<T>
  96. Podemos separar em… val homeUseCase get() = HomeUseCase() object Injector

    { } val viewModels: Map<Class<out ViewModel>, > = () $-> ViewModel mapOf( MainViewModel$::class.java to 
 ) { MainViewModel(homeUseCase) } val viewModelFactory = ViewModelFactory(viewModels) fun viewModelProvider(storeOwner: ViewModelStoreOwner) = ViewModelProvider( storeOwner.viewModelStore, viewModelFactory ) módulos!
  97. Podemos separar em… módulos! class DomainModule { fun homeUseCase() =

    HomeUseCase() } class BaseViewModelModule { fun viewModelFactory( vmMap: Map<Class<out ViewModel>, () -> ViewModel> ) = ViewModelFactory(vmMap) fun viewModelProvider( storeOwner: ViewModelStore, factory: ViewModelFactory ) = ViewModelProvider(storeOwner, factory) }
  98. Podemos separar em… módulos! class DomainModule { fun homeUseCase() =

    HomeUseCase() } class BaseViewModelModule { fun viewModelFactory( vmMap: Map<Class<out ViewModel>, () -> ViewModel> ) = ViewModelFactory(vmMap) fun viewModelProvider( storeOwner: ViewModelStore, factory: ViewModelFactory ) = ViewModelProvider(storeOwner, factory) } class MainModule { fun mainViewModel( homeUseCase: HomeUseCase ) = MainViewModel(homeUseCase) }
  99. val homeUseCase get() = HomeUseCase() object Injector { } val

    viewModels: Map<Class<out ViewModel>, > = () -> ViewModel mapOf( MainViewModel ::class.java to ) { MainViewModel(homeUseCase) } val viewModelFactory = ViewModelFactory(viewModels) fun viewModelProvider(storeOwner: ViewModelStoreOwner) = ViewModelProvider( storeOwner.viewModelStore, viewModelFactory ) Podemos separar em… módulos!
  100. object Injector { } val domainModule = DomainModule() val baseViewModelModule

    = BaseViewModelModule() val mainModule = MainModule() val calculatorModule = CalculatorModule() Podemos separar em… módulos!
  101. object Injector { } $// …Module… private val calculatorModule =

    CalculatorModule() E como expomos as dependências?
  102. object Injector { } $// …Module… private val calculatorModule =

    CalculatorModule() E como expomos as dependências? val calculator = calculatorModule.calculator()
  103. E como expomos as dependências? class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel by lazy { } getViewModel<MainViewModel>() inline fun <reified T : ViewModel> ViewModelStoreOwner .getViewModel() = Injector .viewModelProvider(this) .get(T$::class.java)
  104. E como expomos as dependências? class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle) { … } } val viewModel by lazy { } getViewModel<MainViewModel>() inline fun <reified T : ViewModel> ViewModelStoreOwner .getViewModel() = Injector .viewModelProvider(this) .get(T$::class.java) <— ???
  105. object Injector { } $// …Module… private val calculatorModule =

    CalculatorModule() E como expomos as dependências? val calculator = calculatorModule.calculator()
  106. object Injector { $// …Module… private val calculatorModule = CalculatorModule()

    E como expomos as dependências? val calculator = calculatorModule.calculator() val homeUseCase get() = domainModule.homeUseCase() val vmFactoryMap = mapOf( MainViewModel ::class.java to { mainModule.mainViewModel(homeUseCase) } ) fun viewModelProvider( storeOwner: ViewModelStoreOwner ): ViewModelProvider { return baseViewModelModule.viewModelProvider( storeOwner, baseViewModelModule.viewModelFactory(vmFactoryMap)
  107. object Injector { $// …Module… private val calculatorModule = CalculatorModule()

    E como expomos as dependências? val calculator = calculatorModule.calculator() val homeUseCase get() = domainModule.homeUseCase() val vmFactoryMap = mapOf( MainViewModel ::class.java to { mainModule.mainViewModel(homeUseCase) } ) fun viewModelProvider( storeOwner: ViewModelStoreOwner ): ViewModelProvider { return baseViewModelModule.viewModelProvider( storeOwner, baseViewModelModule.viewModelFactory(vmFactoryMap) { mainModule.mainViewModel(homeUseCase) }
  108. object Injector { $// …Module… private val calculatorModule = CalculatorModule()

    E como expomos as dependências? val calculator = calculatorModule.calculator() val homeUseCase get() = domainModule.homeUseCase() val vmFactoryMap = mapOf( MainViewModel ::class.java to { mainModule.mainViewModel(homeUseCase) } ) fun viewModelProvider( storeOwner: ViewModelStoreOwner ): ViewModelProvider { return baseViewModelModule.viewModelProvider( storeOwner, baseViewModelModule.viewModelFactory(vmFactoryMap) Ainda dá pra melhorar { mainModule.mainViewModel(homeUseCase) }
  109. O elo que faltava No fim das contas, nosso Injector

    não deve gerenciar nossas
 instâncias, apenas fazer seu provisionamento, injetá-las. class HomeViewModel interface BackendApi class MessagingManager class ServiceProvider : Provider val featureAEnabled: Boolean class ConfigFactory<T>
  110. O elo que faltava No fim das contas, nosso Injector

    não deve gerenciar nossas
 instâncias, apenas fazer seu provisionamento, injetá-las. class HomeViewModel interface BackendApi class MessagingManager class ServiceProvider : Provider val featureAEnabled: Boolean class ConfigFactory<T>
  111. O elo que faltava No fim das contas, nosso Injector

    não deve gerenciar nossas
 instâncias, apenas fazer seu provisionamento, injetá-las. class HomeViewModel interface BackendApi class MessagingManager class ServiceProvider : Provider val featureAEnabled: Boolean class ConfigFactory<T> Estamos falando de
 Providers
  112. O elo que faltava Como as classes conversam entre si?

    Injector Module Module Module Provider Provider Provider
  113. O elo que faltava Como as classes conversam entre si?

    Injector Module Module Module Provider Provider Provider BaseViewModelModule
  114. O elo que faltava Como as classes conversam entre si?

    Injector Module Module Module Provider Provider Provider BaseViewModelModule
  115. O elo que faltava Como as classes conversam entre si?

    Injector Module Module Module Provider Provider Provider BaseViewModelModule Provider<ViewModelFactory>
  116. O elo que faltava Como as classes conversam entre si?

    Injector Module Module Module Provider Provider Provider BaseViewModelModule Provider<ViewModelFactory>
  117. O elo que faltava Como as classes conversam entre si?

    Injector Module Module Module Provider Provider Provider BaseViewModelModule Provider<ViewModelFactory> Provider<ViewModelProvider>
  118. O elo que faltava interface Provider<out T> { fun get():

    T } class HomeUseCase_Provider( val domainModule: DomainModule ) : Provider<HomeUseCase> { override fun get() = domainModule.homeUseCase() }
  119. O elo que faltava interface Provider<out T> { fun get():

    T } class HomeUseCase_Provider( val domainModule: DomainModule ) : Provider<HomeUseCase> { override fun get() = domainModule.homeUseCase() } class ViewModelFactory_Provider( val module: BaseViewModelModule, val vmMapProvider: Provider<Map<Class<out ViewModel>, () -> ViewModel >> ) : Provider<ViewModelProvider.Factory> { override fun get() = module.viewModelFactory( vmMapProvider.get()) }
  120. O elo que faltava interface Provider<out T> { fun get():

    T } class HomeUseCase_Provider( val domainModule: DomainModule ) : Provider<HomeUseCase> { override fun get() = domainModule.homeUseCase() } class ViewModelFactory_Provider( val module: BaseViewModelModule, val vmMapProvider: Provider<Map<Class<out ViewModel>, () -> ViewModel >> ) : Provider<ViewModelProvider.Factory> { override fun get() = module.viewModelFactory( vmMapProvider.get()) } Provider<Map<Class<out ViewModel>, () -> ViewModel >>
  121. O elo que faltava interface Provider<out T> { fun get():

    T } class MapProviderFactory<K, out V>( val contributingMap: Map<K, Provider<V >> ) : Provider<Map<K, Provider<V >>> { override fun get() = contributingMap }
  122. O elo que faltava interface Provider<out T> { fun get():

    T
 } class MainViewModel_Provider( val mainModule: MainModule, val homeUseCaseProvider: Provider<HomeUseCase> ) : Provider<MainViewModel> { override fun get() = mainModule.mainViewModel( homeUseCaseProvider.get()) }
  123. O elo que faltava interface Provider<out T> { fun get():

    T
 } class MainViewModel_Provider( val mainModule: MainModule, val homeUseCaseProvider: Provider<HomeUseCase> ) : Provider<MainViewModel> { override fun get() = mainModule.mainViewModel( homeUseCaseProvider.get()) } val vmMapProvider = MapProviderFactory(mapOf( MainViewModel ::class.java to mainViewModelProvider ))
  124. O elo que faltava class ViewModelFactory( val viewModelMap: Map<Class<out ViewModel>,

    ) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { return viewModelMap[modelClass] } } () -> ViewModel> () as T
  125. O elo que faltava class ViewModelFactory( val viewModelMap: Map<Class<out ViewModel>,

    ) : ViewModelProvider.Factory { override fun <T : ViewModel?> create(modelClass: Class<T>): T { return viewModelMap[modelClass] } } Provider<ViewModel >> () as T .get
  126. O elo que faltava interface Provider<out T> { fun get():

    T
 } class ViewModelFactory_Provider( val module: BaseViewModelModule, val vmMapProvider: Provider<Map<Class<out ViewModel>, ) : Provider<ViewModelProvider.Factory> { override fun get() = module.viewModelFactory( vmMapProvider.get()) } () -> ViewModel >>
  127. O elo que faltava interface Provider<out T> { fun get():

    T
 } class ViewModelFactory_Provider( val module: BaseViewModelModule, val vmMapProvider: Provider<Map<Class<out ViewModel>, ) : Provider<ViewModelProvider.Factory> { override fun get() = module.viewModelFactory( vmMapProvider.get()) } Provider<ViewModel >>>
  128. O elo que faltava interface Provider<out T> { fun get():

    T
 } class ViewModelProvider_Provider( val module: BaseViewModelModule, val vmFactoryProvider: Provider<ViewModelProvider.Factory>, val vmStoreOwnerProvider: Provider<ViewModelStoreOwner> ) : Provider<ViewModelProvider> { override fun get() = baseViewModelModule.viewModelProvider( vmStoreOwnerProvider.get() vmFactoryProvider.get() ) }
  129. O elo que faltava interface Provider<out T> { fun get():

    T
 } class ViewModelProvider_Provider( val module: BaseViewModelModule, val vmFactoryProvider: Provider<ViewModelProvider.Factory>, val vmStoreOwnerProvider: Provider<ViewModelStoreOwner> ) : Provider<ViewModelProvider> { override fun get() = baseViewModelModule.viewModelProvider( vmStoreOwnerProvider.get() vmFactoryProvider.get() ) } val vmStoreOwnerProvider: Provider<ViewModelStoreOwner>
  130. O elo que faltava interface Provider<out T> { fun get():

    T
 } class ViewModelProvider_Provider( val module: BaseViewModelModule, val vmFactoryProvider: Provider<ViewModelProvider.Factory>, ) : Provider<ViewModelProvider> { override fun get() = baseViewModelModule.viewModelProvider( vmStoreOwnerProvider.get() vmFactoryProvider.get() )
 } val vmStoreOwnerProvider: Provider<ViewModelStoreOwner>
  131. O elo que faltava interface Provider<out T> { fun get():

    T
 } class ViewModelProvider_Provider( val module: BaseViewModelModule, val vmFactoryProvider: Provider<ViewModelProvider.Factory>, ) : Provider<ViewModelProvider> { override fun get() = baseViewModelModule.viewModelProvider( vmStoreOwnerProvider.get() vmFactoryProvider.get() )
 } val vmStoreOwnerProvider: ViewModelStoreOwner
  132. object Injector { } E como expomos as dependências? val

    domainModule = DomainModule() val baseViewModelModule = BaseViewModelModule() val mainModule = MainModule()
  133. object Injector { } E como expomos as dependências? val

    domainModule = DomainModule() val baseViewModelModule = BaseViewModelModule() val mainModule = MainModule() val providerHomeUseCase = HomeUseCase_Provider( domainModule) val providerMainViewModel = MainViewModel_Provider( mainModule, providerHomeUseCase val providerVmMap = MapProviderFactory(mapOf( MainViewModel ::class.java to providerMainViewModel)) val providerVmFactory = ViewModelFactory_Provider( baseViewModelModule, providerVmMap)
  134. object Injector { } E como expomos as dependências? val

    domainModule = DomainModule() val baseViewModelModule = BaseViewModelModule() val mainModule = MainModule() val providerHomeUseCase = HomeUseCase_Provider( domainModule) val providerMainViewModel = MainViewModel_Provider( mainModule, providerHomeUseCase val providerVmMap = MapProviderFactory(mapOf( MainViewModel$::class.java to providerMainViewModel)) val providerVmFactory = ViewModelFactory_Provider( baseViewModelModule, providerVmMap)
  135. object Injector { } E como expomos as dependências? val

    domainModule = DomainModule() val baseViewModelModule = BaseViewModelModule() val mainModule = MainModule() val providerHomeUseCase = HomeUseCase_Provider( domainModule) val providerMainViewModel = MainViewModel_Provider( mainModule, providerHomeUseCase val providerVmMap = MapProviderFactory(mapOf( MainViewModel$::class.java to providerMainViewModel)) val providerVmFactory = ViewModelFactory_Provider( baseViewModelModule, providerVmMap)
  136. } E como expomos as dependências? object Injector { val

    domainModule = DomainModule() val baseViewModelModule = BaseViewModelModule() val mainModule = MainModule() val providerHomeUseCase = HomeUseCase_Provider( domainModule) val providerMainViewModel = MainViewModel_Provider( mainModule, providerHomeUseCase val providerVmMap = MapProviderFactory(mapOf( MainViewModel$::class.java to providerMainViewModel)) val providerVmFactory = ViewModelFactory_Provider( baseViewModelModule, providerVmMap)
  137. } E como expomos as dependências? fun viewModelProvider( storeOwner: ViewModelStoreOwner

    ): ViewModelProvider { return ViewModelProvider_Provider( baseViewModelModule, providerVmFactory, storeOwner ).get() } object Injector { val domainModule = DomainModule() val baseViewModelModule = BaseViewModelModule() val mainModule = MainModule() val providerHomeUseCase = HomeUseCase_Provider( domainModule) val providerMainViewModel = MainViewModel_Provider( mainModule, providerHomeUseCase val providerVmMap = MapProviderFactory(mapOf( MainViewModel$::class.java to providerMainViewModel)) val providerVmFactory = ViewModelFactory_Provider( baseViewModelModule, providerVmMap)
  138. object Injector { } $// …Module… private val calculatorModule =

    CalculatorModule() E como expomos singletons?
  139. object Injector { } $// …Module… private val calculatorModule =

    CalculatorModule() E como expomos singletons? val providerCalculator = Calculator_Provider( calculatorModule)
  140. object Injector { } $// …Module… private val calculatorModule =

    CalculatorModule() E como expomos singletons? val providerCalculator = Calculator_Provider( calculatorModule) ???
  141. interface Provider<out T> { fun get(): T } E como

    expomos singletons? class SingleProvider<out T>( val factory: Provider<T> ) : Provider<T> { private var instance: T? = null override fun get(): T { return instance ?: factory.get().also { instance = it } } }
  142. object Injector { } $// …Module… private val calculatorModule =

    CalculatorModule() E como expomos singletons? val providerCalculator =
  143. object Injector { } $// …Module… private val calculatorModule =

    CalculatorModule() E como expomos singletons? val providerCalculator = SingleProvider( Calculator_Provider(calculatorModule) )
  144. Onde chegamos Vimos premissas básicas para alcançarmos uma boa estrutura

    de injeção de dependências. Abordamos três papéis fundamentais nessa estrutura:
 - Raiz de Composição (incorporado por nosso Injector)
 - Catalogar como construir instâncias (através de Modules)
 - Criar e guardar instâncias (através de Providers) CompositionRoot Module Module Module Provider Provider Provider BaseViewModelModule Provider<ViewModelFactory> Provider<ViewModelProvider>
  145. Onde chegamos Fato é: essa estrutura precisa de muito código

    pra funcionar, logo é sensato delegar este trabalho a uma framework. i.e.: Koin, Dagger, Katana, Kodein…
  146. Onde chegamos Fato é: essa estrutura precisa de muito código

    pra funcionar, logo é sensato delegar este trabalho a uma framework. i.e.: Koin, Dagger, Katana, Kodein… Existem diferenças entre a implementação de cada framework, mas
 a base estrutural é a mesma. i.e.: Os providers do Koin (chamados de Beans), ao invés
 de receberem modules e outros providers, recebem a raiz da
 composição diretamente, enquanto os Providers do Dagger
 funcionam como vimos.
  147. Onde chegamos Fato é: essa estrutura precisa de muito código

    pra funcionar, logo é sensato delegar este trabalho a uma framework. i.e.: Koin, Dagger, Katana, Kodein… Existem diferenças entre a implementação de cada framework, mas
 a base estrutural é a mesma. i.e.: Os providers do Koin (chamados de Beans), ao invés
 de receberem modules e outros providers, recebem a raiz da
 composição diretamente, enquanto os Providers do Dagger
 funcionam como vimos. Não apenas agora vimos como esses frameworks funcionam,
 agora podemos usar isto em nosso favor.
  148. Para onde ir Podemos tentar entender como injetar dependências em

    nossas activities sem ter de buscar explicitamente na raiz de composição
  149. Para onde ir Scopes - Expandindo a raiz de composição

    em galhos focados em partes específicas do sistema. Podemos tentar entender como injetar dependências em nossas activities sem ter de buscar explicitamente na raiz de composição
  150. Para onde ir Scopes - Expandindo a raiz de composição

    em galhos focados em partes específicas do sistema. Weak references - Dependências que podem ser reutilizadas porém são facilmente coletadas pelo GC quando for necessário. Podemos tentar entender como injetar dependências em nossas activities sem ter de buscar explicitamente na raiz de composição
  151. Para onde ir Scopes - Expandindo a raiz de composição

    em galhos focados em partes específicas do sistema. Weak references - Dependências que podem ser reutilizadas porém são facilmente coletadas pelo GC quando for necessário. Assisted injection - Quando uma classe tem dependências em mais de uma origem além de nossa raiz de composição. (WorkManager) Podemos tentar entender como injetar dependências em nossas activities sem ter de buscar explicitamente na raiz de composição
  152. Para onde ir Scopes - Expandindo a raiz de composição

    em galhos focados em partes específicas do sistema. Weak references - Dependências que podem ser reutilizadas porém são facilmente coletadas pelo GC quando for necessário. Assisted injection - Quando uma classe tem dependências em mais de uma origem além de nossa raiz de composição. (WorkManager) Entender bem as nuances e poderes do seu framework preferido e começar a destravar os seus poderes especiais a seu favor. Podemos tentar entender como injetar dependências em nossas activities sem ter de buscar explicitamente na raiz de composição
  153. Bibliografia e Recomendações Dagger 2 : Check — SingleCheck —

    DoubleCheck … Scopes,
 por Garima Jain
 https://proandroiddev.com/dagger-2-check-singlecheck-doublecheck-scopes-4ee48fc31736 Projeto KOIN Core (e também o projeto ViewModel)
 https://github.com/InsertKoinIO/koin/tree/master/koin-projects/koin-core Dagger 2 on Android: Assisted Injection
 por Fred Porcíuncula, com talk de Jake Wharton na droidCon 2018
 https://proandroiddev.com/dagger-assisted-injection-2002885b3cba That Missing Guide: How to use Dagger2
 por Gabor Varadi
 https://medium.com/@Zhuinden/that-missing-guide-how-to-use-dagger2-ef116fbea97
  154. N Ó S M O V E M O S

    O M U N D O . RIO SÃO PAULO BH RECIFE Centro Av. Presidente Wilson, 231 29º andar (21) 2240-2030 Cidade Monções Av. Nações Unidas, 11.541 3º andar
 (11) 4119-0449 Savassi Av. Getúlio Vargas, 671 Sala 800 - 8º andar (31) 3360-8900 Ilha do Leite Rua Sen. José Henrique, 199 2º andar (81) 3018-6299 W W W. C O N C R E T E . C O M . B R