Add the dependency below to your module's build.gradle.kts
file:
dependencies {
implementation("io.github.composegears:leviathan:$version")
}
sourceSets {
commonMain.dependencies {
implementation("io.github.composegears:leviathan:$version")
}
}
Create Module
(recommend to use object
) and extends from Leviathan
class
Create fields using one of 2 functions:
- Use
by instance
to create single-object-delegate (same instance upon every access) - Use
by factory
to create factory-delegate (new instance upon each access)
Use by (instance|factory)<Interface>{InterfaceImpl}
to hide impl class
Declare you repositories
class SampleRepository()
class SampleRepositoryWithParam(val param: Int)
class SampleRepositoryWithDependency(val dependency: SampleRepository)
interface SampleInterfaceRepo
class SampleInterfaceRepoImpl : SampleInterfaceRepo
Create module
class Module : Leviathan() {
val lazyRepository by instance(::SampleRepository)
val nonLazyRepository by instance(false, ::SampleRepository)
val repositoryWithParam by factory { SampleRepositoryWithParam(1) }
val repositoryWithDependency by instance { SampleRepositoryWithDependency(lazyRepository) }
val interfaceRepo by instance<SampleInterfaceRepo>(::SampleInterfaceRepoImpl)
}
Dependencies usage:
fun foo() {
val repo = Module.lazyRepository
//...
}
class Model(
val repo: SampleRepository = Module.lazyRepository
) {
//...
}
class Model() {
private val repo = Module.lazyRepository
//...
}
- HttpClient
- WeatherRepository <- HttpClient
- NewsRepository <- HttpClient
- App <- WeatherRepository, NewsRepository
- Http Client Module
class HttpClient { // ... }
- Weather service module
class WeatherRepository(client: HttpClient) { // ... }
- News service module
class NewsRepository(client: HttpClient) { // ... }
- App service module
object AppModule : Leviathan() { private val httpClient by instance { HttpClient() } val weatherRepository by instance { WeatherRepository(httpClient) } val newsRepository by instance { NewRepository(httpClient) } }
In order to create good & testable classes recommend to use advanced scenario
- declare dependencies
class DataRepository //... class ApiRepository //...
- declare module interface (data/domain modules)
interface DataModule { val dataRepository: DataRepository } interface ApiModule { val apiRepository: ApiRepository }
- Create
AppModule
and inherit from interfaces(step #2) andLeviathan
object AppModule : DataModule, ApiModule, Leviathan() { override val dataRepository: DataRepository by instance(::DataRepository) override val apiRepository: ApiRepository by instance(::ApiRepository) }
- Create Models (or any other classes) base on interfaces from step #2
class Model(apiModule: ApiModule = AppModule){ val api = apiModule.apiRepository fun foo(){/*...*/} }
Now you can make tests and have easy way to mock your data:
@Test
fun ModelTests(){
val model = Model(object : ApiModule {
override val apiRepository: ApiRepository
get() = ApiRepository() // mock
})
model.foo()
}
Developed by ComposeGears 2024
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.