深入理解 Android 架构 Clean Architecture(解析篇)

深入理解 Android 架构 Clean Architecture(解析篇)_第1张图片
上期回顾:深入理解 Android 架构 Clean Architecture(介绍篇)

如何分层

首先代码将会独立分为三层:

  • Presentation Layer(表示层)
  • Domain Layer(领域层)
  • Data Layer(数据层)

Data Layer - 数据层

Data Layer(数据层)是三层之中最底层,它包含应用数据和业务逻辑。业务逻辑决定应用的价值,它包含决定应用如何创建、存储和更改应用数据。
深入理解 Android 架构 Clean Architecture(解析篇)_第2张图片
Data Layer(数据层)由一个或多个 Repository(存储库 )组成,其中每个存储库可包含一个或多个 Data Source(数据源)。数据源负责提供应用所需的数据,它们可能是远程API或者本地数据库。

Repository

Repository 在数据层中承担了抽象数据访问、集中管理数据来源以及简化数据访问的作用,为业务逻辑提供了清晰且统一的数据访问接口。

Data Source

它是应用程序与外部数据之间的桥梁,负责管理数据的存储、获取和传输,并通过 Repository 等抽象层向其他部分提供统一的数据访问接口。

总结:Data Layer(数据层)负责存储、管理以及提供应用数据。


Domain Layer - 领域层

Domain Layer(领域层)位于 Data Layer(数据层)和 Presentation(表示层)之间,它可以简化应用架构、易于理解,具有扩展和易于测试。
深入理解 Android 架构 Clean Architecture(解析篇)_第3张图片
Domain Layer(领域层)通常由 Use Case 和领域模型组成,负责处理应用程序的业务逻辑和核心功能。业务逻辑与UI逻辑不同,UI逻辑定义如何在屏幕上显示内容,而业务逻辑定义如何处理事件和数据更改。

在小型应用上,业务逻辑通常在 ViewModel 或者数据层中进行,但是随着应用功能不断地发展,ViewModel会变得越来越重,因此将所有业务逻辑合并到领域层是非常有意义的。

Domain Layer(领域层)不会负责数据的显示,因为这是表现层的工作,也不负责获取和存储数据,这是数据层的工作。

Use Case

命名:功能名 + UsuCase
作用:封装可复用的业务逻辑、组合多个存储库的数据
示例代码:LoginUseCase 负责处理用户登录的业务逻辑。在登录之前进行一系列的邮箱、密码格式验证后调用下层的 repository 执行登录操作,最后表示层在用户触发登录操作后调用该 Use Case。

class LoginUseCase(
      private val repository: AuthRepository,
) {
      suspend operator fun invoke(
            email: String, 
            password: String
      ): LoginResult {
            //在这里处理业务逻辑
            val emailError = ValidationUtil.validateEmail(email)
            val passwordError = if (password.isBlank()) AuthError.FieldEmpty else null
            if (emailError != null || passwordError != null) {
                  return LoginResult(
                        emailError = emailError, passwordError = passwordError
                  )
            }

            return LoginResult(
                  result = repository.login(email.trim(), password.trim())
            )
      }
}

因为 Use Case 从始至终都专注于处理业务一件事,所以它可以使用 Kotlin 中的调用运算符从而在 ViewModel 中像普通函数调用它即可。这样做也符合 Clean Architecture 中分离关注点、单一职责的原则,提高复用性和测试性,清晰的代码结构帮助开发者后期维护。

@HiltViewModel
class LoginViewModel @Inject constructor(
      private val loginUseCase: LoginUseCase,
) : ViewModel() {

      ...

      private fun login() {
            viewModelScope.launch {
                 ...
                 
                  val loginError = loginUseCase(
                        email = emailState.value.text,
                        password = passwordState.value.text
                  )
                  
                  ...
            }
      }
}

Domain Model

在领域层,通常会定义领域模型,即业务对象和实体。一般数据源返回的模型可能不是其他层所完全需要的模型,通俗点来讲服务器返回了一篇文章的所有信息例如:编号、内容、标题、时间、类型、作者等等,但是我们只需要编号标题和内容,其它数据不需要,所有需要领域层定义对应的领域模型。

示例代码:

/** 数据层的模型 */ 
data class ArticleModel(
    val id:Int,
    val title:String,
    val content:String,
    val timestamp:Long,
    val author:String,
    val type:String
){
    // 映射成领域层的模型
    fun toArticle():Article{
        return Article(
            id = id,
            title = title,
            content = content
        )
    }
}
/** 领域层的模型 */ 
data class Article(
    val id:Int,
    val title:String,
    val content:String,
)

这不仅使代码更加整洁,还能更好地隔离潜在的问题,使每一层定义自己所需的模型。

Domain Layer(领域层)负责应用程序的核心业务逻辑


Presentation Layer - 表示层

Presentation Layer(表示层)位于三层的最外层,它负责处理与用户界面(UI)交互相关的事务。
深入理解 Android 架构 Clean Architecture(解析篇)_第4张图片
Presentation Layer(表示层)在官方说明文档中是由UI组件和状态持有者组成,但是我个人觉得划分为三部分会更加清晰,分别为UI组件、UI的状态以及 ViewModel 三部分组成。

UI Elements

UI Elements 一般是指用户界面中的元素,负责向用户展示信息、接收输入或执行特定的交互功能。例如在 Compose 中的 Screen 或者某一个组件,也可以是View系统中的Activity、Fragment。

UI State

UI State 是指用户界面的当前状态或条件,其中包含了影响用户界面显示和行为的各种数据。UI State 大到可以作为一个页面的状态,小到为一个组件的状态。
示例代码:

// 关于用户列表的状态
data class PersonListState(
      val isLoading: Boolean = false
      val users: List<UserItem> = emptyList(),
)

ViewModel

ViewModel 主要负责处理用户与界面交互的UI逻辑,在表示层中是扮演着状态持有者的角色,它会存储并公开界面要使用的状态,界面状态是经过 ViewModel 转换的应用数据。
深入理解 Android 架构 Clean Architecture(解析篇)_第5张图片
首先 UI 会引用 ViewModel 公开的状态,随即界面向 ViewModel 发送用户的事件,然后 ViewModel 进行一系列的处理后更新状态,状态一旦更改就会驱动UI进行刷新,最后呈现给用户,这就形成了单向的数据流也是MVI设计模式的核心。
深入理解 Android 架构 Clean Architecture(解析篇)_第6张图片
示例代码:

@Composable
fun PersonListScreen(
      viewModel: PersonListViewModel = hiltViewModel()
) {
      val state = viewModel.state.value

      Column(
            modifier = Modifier.fillMaxSize()
      ) {
            // 发起UI事件
            Button(onClick = {
                  viewModel.getPersonList(id)
            }) {
                  Text(text = "获取数据")
            }

            LazyColumn(
                  modifier = Modifier.fillMaxSize()
            ){
                items(state.users) { ... }
            }
      }
}
@HiltViewModel
class PersonListViewModel @Inject constructor(
      ...
) : ViewModel() {

    // ---  状态  ---
    private val _uiState = mutableStateOf(PersonListState())
    val uiState: State<PersonListState> = _uiState
    
    // ---  这里统一处理用户事件  ---
    fun onEvent(event:PersonEvent){
        when(event){
            ...
            is PersonEvent.GetData -> getPersonList()
        }
    }
    
    
    private fun getPersonList() {
        viewModelScope.launch {
            //在获取用户列表时会更新状态为加载中
            _state.value = state.value.copy(isLoading = true)

            //获取完成后根据结果更新状态
            when (val result = personUseCases.getPersonList()) {
                is Resource.Error -> {
                    //加载失败发出加载失败的UI事件
                    ...
                    _state.value = state.value.copy(isLoading = false)
                }
                
                is Resource.Success -> {
                    //加载成功后更新状态的值
                    _state.value = state.value.copy(
                        users = result.data ?: emptyList(),
                        isLoading = false
                    )
                }
            }
        }
    }
}

Presentation Layer(表现层)负责处理用户界面的显示逻辑以及协调用户交互操作呈现数据。


最后,可以关注一下本人的公众号,会不定期发布一些关于 Android、Kotlin、Jetpack Compose相关的学习笔记和知识。
在这里插入图片描述

你可能感兴趣的:(Clean,Architecture,android,架构,kotlin,android-studio,android,jetpack)