Android+Kotlin中实践Clean Architecture

104 篇文章 29 订阅

Clean Architecture


在这里插入图片描述
Clean Architecture 由Robert C. Martin(Uncle Bob)发布于2012年 :
http://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

目前被作为项目结构组织的最佳范式被广泛熟知,连Android官方的MVVM示例项目中也有所使用。Clean架构很好地实践了SLOID原则,具有以下优点

  • 分层设计贯彻了关注点分离
  • 高度抽象,适用于各类型的业务
  • 各层之间保持松耦合
  • 便于测试

“Clean code always looks like it was written by someone who cares.”
— Michael Feathers

本文结合具体的Sample,介绍在Android+Kotlin项目中如何落地Clean架构:
https://github.com/rakshit444/news-sample-app


分层设计


在这里插入图片描述

  • Domain layer(领域层):
    承担业务逻辑,一般与平台无关,所由纯Kotlin实现,不应该依赖Android相关的SDK
  • Data layer(数据层):
    为领域层服务,通过实现领域层的接口为其获取数据,一般也是纯Kotlin代码
  • Presentation layer(表示层):
    依赖领域层获取数据,并通过android实现UI渲染逻辑

Domain Layer 领域层


这将是三层中最通用的一层。它将连接表示层和数据层,用来执行具体业务逻辑
在这里插入图片描述

UseCases

UseCases是一段独立逻辑承载和执行单元,UseCase的划分粒度越粗就越抽象,越是利于复用,例如GetNewsUseCase:

//GetNewsUseCase.kt
class GetNewsUseCase(private val transformer: FlowableRxTransformer<NewsSourcesEntity>,
                     private val repositories: NewsRepository): BaseFlowableUseCase<NewsSourcesEntity>(transformer){

    override fun createFlowable(data: Map<String, Any>?): Flowable<NewsSourcesEntity> {
        return repositories.getNews()
    }

    fun getNews(): Flowable<NewsSourcesEntity>{
        val data = HashMap<String, String>()
        return single(data)
    }
}

GetNewsUseCase返回一个Flowable供UI层订阅。两个参数

  • transformer:决定逻辑执行在哪个线程
  • repositories:提供接口给数据层获取数据

Repositories

提供给数据层的interface


Data Layer 数据层


数据层用来请求数据,数据层的逻辑应该具有可复用性,相对于UI层更加稳定
在这里插入图片描述

api & db

api和db分别提供远程和本地的数据源,android中可能体现为retrofit和sqllite等

repository

repository中是数据层对于领域层的接口实现,例如:

//NewsRepositoryImpl.kt
class NewsRepositoryImpl(private val remote: NewsRemoteImpl,
                         private val cache: NewsCacheImpl) : NewsRepository {

    override fun getLocalNews(): Flowable<NewsSourcesEntity> {
        return cache.getNews()
    }

    override fun getRemoteNews(): Flowable<NewsSourcesEntity> {
        return remote.getNews()
    }

    override fun getNews(): Flowable<NewsSourcesEntity> {
        val updateNewsFlowable = remote.getNews()
        return cache.getNews()
                .mergeWith(updateNewsFlowable.doOnNext{
                    remoteNews -> cache.saveArticles(remoteNews)
                })
    }
}

Repository中封装了对数据源的获取方式,请求的数据可以来自本地或远程,但对外不必暴露具体细节


Presenter Layer 表现层


表现层负责UI渲染的逻辑。可以等同于各种MVX框架中的V层,不应承担任何业务逻辑
在这里插入图片描述

di

di中存放各种表现层的依赖对象,例如一些工具类,ViewModel、UseCase等等。di一般可以使使用dagger、koin等di框架实现。本例中使用的是koin,因为它相对于dagger更加简单,适合规模不大的项目使用

ViewModel

Store and manage UI-related data in a lifecycle conscious way. It allows data to survive configuration changes such as screen rotations.

class NewsViewModel(private val getNewsUseCase: GetNewsUseCase,
                    private val mapper: Mapper<NewsSourcesEntity, NewsSources>) : BaseViewModel() {

    companion object {
        private val TAG = "viewmodel"
    }

    var mNews = MutableLiveData<Data<NewsSources>>()

    fun fetchNews() {
        val disposable = getNewsUseCase.getNews()
                .flatMap { mapper.Flowable(it) }
                .subscribe({ response ->
                    Log.d(TAG, "On Next Called")
                    mNews.value = Data(responseType = Status.SUCCESSFUL, data = response)
                }, { error ->
                    Log.d(TAG, "On Error Called")
                    mNews.value = Data(responseType = Status.ERROR, error = Error(error.message))
                }, {
                    Log.d(TAG, "On Complete Called")
                })

        addDisposable(disposable)
    }

    fun getNewsLiveData() = mNews
}

项目中使用ViewModel存储UI的状态。Data作为一个统一的Wrapper,处理数据请求状态

data class Data<RequestData>(var responseType: Status, var data: RequestData? = null, var error: Error? = null)

enum class Status { SUCCESSFUL, ERROR, LOADING }

MVVM相对于MVP中,不再重度依赖接口,且能感知生命周期。

这里BaseViewModel通过CompositeDisposable 收集所有的订阅,然后再onCleared中统一释放


数据流向


Android项目中的Clean架构,整体数据流向如下图:相对于普通的MVVM,相当于把ViewModel的职责进一步细分成多个UseCase,避免ViewModel的膨胀
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值