Last active
November 23, 2021 08:20
-
-
Save nomisRev/4569b3035a7f2bbc51a9bee6fb27dabc to your computer and use it in GitHub Desktop.
Receiver Context Dependency Injection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.example.sample | |
| import arrow.core.* | |
| import arrow.core.computations.either | |
| import arrow.fx.coroutines.raceN | |
| public data class NewsItem(val id: String) | |
| public data class Detail(val id: String, val content: String) | |
| public object Failure | |
| public class Db | |
| public class Nw | |
| //<editor-fold desc="Singleton"> | |
| public class AppModule(public val retrofit: Nw, public val db: Db) | |
| public val appModule: AppModule = AppModule(Nw(), Db()) | |
| //</editor-fold> | |
| //<editor-fold desc="News List"> | |
| public interface NewsRepository { | |
| public suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>> | |
| fun zip(other: NewsRepository): NewsRepository = | |
| object : NewsRepository { | |
| override suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>> = | |
| [email protected]().zip(other.headlines()) { nw, db -> nw + db } | |
| } | |
| } | |
| class NewsDatabaseImpl(private val database: Db) : NewsRepository { | |
| override suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>> = | |
| nonEmptyListOf( | |
| NewsItem("4"), | |
| NewsItem("5"), | |
| NewsItem("6"), | |
| ).right() | |
| } | |
| class NewsNetworkImpl(private val network: Nw) : NewsRepository { | |
| override suspend fun headlines(): Either<Failure, NonEmptyList<NewsItem>> = | |
| nonEmptyListOf( | |
| NewsItem("1"), | |
| NewsItem("2"), | |
| NewsItem("3"), | |
| ).right() | |
| } | |
| //</editor-fold> | |
| //<editor-fold desc="Detail"> | |
| public interface DetailRepository { | |
| public suspend fun detail(newsItem: NewsItem): Either<Failure, Detail> | |
| } | |
| public class DetailRepositoryImpl( | |
| private val network: DetailRepository, | |
| private val database: DetailRepository | |
| ) : DetailRepository { | |
| override suspend fun detail(newsItem: NewsItem): Either<Failure, Detail> = | |
| either { | |
| raceN( | |
| { network.detail(newsItem).bind() }, | |
| { database.detail(newsItem).bind() } | |
| ).merge() | |
| } | |
| } | |
| class NetworkDetailDataSource(private val retrofit: Nw): DetailRepository { | |
| override suspend fun detail(newsItem: NewsItem): Either<Failure, Detail> = | |
| Detail(newsItem.id, "Nw: Content of $newsItem").right() | |
| } | |
| class DatabaseDetailDataSource(private val db: Db): DetailRepository { | |
| override suspend fun detail(newsItem: NewsItem): Either<Failure, Detail> = | |
| Detail(newsItem.id, "Db: Content of $newsItem").right() | |
| } | |
| //</editor-fold> | |
| interface Module: NewsRepository, DetailRepository | |
| fun module(newsRepository: NewsRepository, detailRepository: DetailRepository): Module = | |
| object : Module, NewsRepository by newsRepository, DetailRepository by detailRepository { } | |
| suspend fun Module.program(): Either<Failure, NonEmptyList<Detail>> = | |
| headlines().flatMap { | |
| it.traverseEither { detail(it) } | |
| } | |
| public suspend fun main() { | |
| val news: NewsRepository = | |
| NewsNetworkImpl(appModule.retrofit).zip(NewsDatabaseImpl(appModule.db)) | |
| val detail: DetailRepository = | |
| DetailRepositoryImpl( | |
| NetworkDetailDataSource(appModule.retrofit), | |
| DatabaseDetailDataSource(appModule.db) | |
| ) | |
| val module = module(news, detail) | |
| val detailPages = module.program() | |
| println(detailPages) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment