在这里插入图片描述

项目概述

应用架构是决定应用质量和可维护性的关键因素。在 KMP 框架下,我们需要遵循最佳实践来构建可扩展、可测试和易于维护的应用。本文详细介绍了如何在 Kotlin Multiplatform 中实现高效的应用架构,包括分层架构、依赖注入、测试策略和鸿蒙系统特定的架构考虑。

本篇更加偏“方法论 + 模板”,适用于:

  • 从零搭建一个 KMP + 鸿蒙 的多端项目,希望一开始就有清晰架构;
  • 已有项目逐步引入 KMP,希望整理业务层/数据层,减少平台间重复代码;
  • 希望在多端统一测试、优化性能、提升可维护性。

目标是给出一套可以落地的参考架构

  • 上层 UI/Ability/页面与平台强相关;
  • 中层业务用例、状态管理与 ViewModel 主要放在 commonMain
  • 底层数据访问和平台能力通过 expect/actual 与接口适配。

第一部分:架构核心概念

分层架构

// commonMain/kotlin/com/example/architecture/layers/PresentationLayer.kt
// 表示层 - 处理 UI 逻辑和用户交互
interface PresentationLayer {
    fun displayData(data: Any)
    fun showError(error: String)
    fun showLoading(isLoading: Boolean)
}

// commonMain/kotlin/com/example/architecture/layers/DomainLayer.kt
// 业务层 - 包含业务逻辑和用例
interface UseCase<in Input, out Output> {
    suspend fun execute(input: Input): Output
}

data class GetUserUseCase(private val repository: UserRepository) : UseCase<String, User> {
    override suspend fun execute(input: String): User {
        return repository.getUserById(input)
    }
}

// commonMain/kotlin/com/example/architecture/layers/DataLayer.kt
// 数据层 - 处理数据获取和存储
interface Repository<T> {
    suspend fun getAll(): List<T>
    suspend fun getById(id: String): T?
    suspend fun save(item: T): Boolean
    suspend fun delete(id: String): Boolean
}

interface UserRepository : Repository<User> {
    suspend fun getUserByEmail(email: String): User?
}

这一部分展示的是经典的三层架构在 KMP 下的拆分方式

  • 表示层(PresentationLayer):关注 UI 状态、用户交互,与具体平台 UI 技术(Compose/SwiftUI/鸿蒙 UI)结合;
  • 业务层(UseCase):聚焦业务规则与用例组合,尽量写在 commonMain,方便跨端复用;
  • 数据层(Repository):封装网络、本地数据库、缓存等数据来源,通过接口隐藏实现细节。

在 KMP 项目中,这种分层可以让你:

  • 将与具体平台强相关的部分(Ability/Activity/Controller)限制在少数边界层;
  • 将复杂业务流程和数据处理逻辑抽出到共享模块,减少“多端各写一遍”的情况;
  • 提高单元测试覆盖率:绝大多数业务逻辑可以在 commonTest 中直接测试。

依赖注入

// commonMain/kotlin/com/example/architecture/di/Container.kt
class DIContainer {
    private val singletons = mutableMapOf<String, Any>()
    private val factories = mutableMapOf<String, () -> Any>()
    
    inline fun <reified T> singleton(name: String = T::class.simpleName!!, factory: () -> T) {
        factories[name] = factory
    }
    
    inline fun <reified T> get(name: String = T::class.simpleName!!): T {
        return singletons.getOrPut(name) {
            factories[name]?.invoke() ?: throw IllegalArgumentException("No factory for $name")
        } as T
    }
}

// 使用示例
val container = DIContainer().apply {
    singleton<UserRepository> { UserRepositoryImpl() }
    singleton<GetUserUseCase> { GetUserUseCase(get()) }
    singleton<UserViewModel> { UserViewModel(get()) }
}

状态管理

// commonMain/kotlin/com/example/architecture/state/StateHolder.kt
sealed class UIState<T> {
    object Loading : UIState<Nothing>()
    data class Success<T>(val data: T) : UIState<T>()
    data class Error(val exception: Exception) : UIState<Nothing>()
}

class StateHolder<T> {
    private val _state = MutableStateFlow<UIState<T>>(UIState.Loading)
    val state: StateFlow<UIState<T>> = _state.asStateFlow()
    
    suspend fun setState(newState: UIState<T>) {
        _state.emit(newState)
    }
}

第二部分:设计模式

MVI 模式

// commonMain/kotlin/com/example/architecture/mvi/MVIArchitecture.kt
// Model - 数据模型
data class UserModel(
    val id: String,
    val name: String,
    val email: String
)

// View - UI 接口
interface UserView {
    fun render(state: UserViewState)
}

// Intent - 用户意图
sealed class UserIntent {
    data class LoadUser(val userId: String) : UserIntent()
    data class UpdateUser(val user: UserModel) : UserIntent()
    object DeleteUser : UserIntent()
}

// ViewState - 视图状态
data class UserViewState(
    val isLoading: Boolean = false,
    val user: UserModel? = null,
    val error: String? = null
)

// Presenter - 业务逻辑
class UserPresenter(private val useCase: GetUserUseCase) {
    suspend fun handleIntent(intent: UserIntent): UserViewState {
        return when (intent) {
            is UserIntent.LoadUser -> {
                try {
                    val user = useCase.execute(intent.userId)
                    UserViewState(user = user)
                } catch (e: Exception) {
                    UserViewState(error = e.message)
                }
            }
            else -> UserViewState()
        }
    }
}

MVVM 模式

// commonMain/kotlin/com/example/architecture/mvvm/MVVMArchitecture.kt
class UserViewModel(private val useCase: GetUserUseCase) {
    private val _user = MutableStateFlow<User?>(null)
    val user: StateFlow<User?> = _user.asStateFlow()
    
    private val _isLoading = MutableStateFlow(false)
    val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
    
    private val _error = MutableStateFlow<String?>(null)
    val error: StateFlow<String?> = _error.asStateFlow()
    
    fun loadUser(userId: String) {
        GlobalScope.launch {
            _isLoading.emit(true)
            try {
                val user = useCase.execute(userId)
                _user.emit(user)
            } catch (e: Exception) {
                _error.emit(e.message)
            } finally {
                _isLoading.emit(false)
            }
        }
    }
}

第三部分:测试策略

单元测试

// commonTest/kotlin/com/example/architecture/UserRepositoryTest.kt
class UserRepositoryTest {
    private lateinit var repository: UserRepository
    
    @Before
    fun setup() {
        repository = UserRepositoryImpl()
    }
    
    @Test
    fun testGetUserById() = runTest {
        val userId = "123"
        val user = repository.getUserById(userId)
        
        assertEquals("123", user?.id)
        assertEquals("John Doe", user?.name)
    }
    
    @Test
    fun testSaveUser() = runTest {
        val user = User("456", "Jane Doe", "jane@example.com")
        val result = repository.save(user)
        
        assertTrue(result)
    }
}

集成测试

// commonTest/kotlin/com/example/architecture/UserUseCaseTest.kt
class UserUseCaseTest {
    private lateinit var useCase: GetUserUseCase
    private lateinit var repository: UserRepository
    
    @Before
    fun setup() {
        repository = MockUserRepository()
        useCase = GetUserUseCase(repository)
    }
    
    @Test
    fun testExecuteGetUser() = runTest {
        val user = useCase.execute("123")
        
        assertNotNull(user)
        assertEquals("John Doe", user.name)
    }
}

第四部分:性能优化

内存管理

// commonMain/kotlin/com/example/architecture/performance/MemoryOptimization.kt
class MemoryOptimizedCache<K, V>(private val maxSize: Int = 100) {
    private val cache = LinkedHashMap<K, V>(maxSize, 0.75f, true)
    
    fun get(key: K): V? = cache[key]
    
    fun put(key: K, value: V) {
        if (cache.size >= maxSize) {
            val iterator = cache.iterator()
            iterator.next()
            iterator.remove()
        }
        cache[key] = value
    }
    
    fun clear() = cache.clear()
}

并发优化

// commonMain/kotlin/com/example/architecture/performance/ConcurrencyOptimization.kt
class OptimizedRepository(
    private val dispatcher: CoroutineDispatcher = Dispatchers.Default
) {
    suspend fun fetchDataConcurrently(ids: List<String>): List<Data> {
        return withContext(dispatcher) {
            ids.map { id ->
                async { fetchData(id) }
            }.awaitAll()
        }
    }
}

第五部分:鸿蒙系统特定考虑

鸿蒙应用架构

// ohos/kotlin/com/example/architecture/HarmonyOSArchitecture.kt
// Ability 层 - 鸿蒙特定的生命周期管理
class UserAbility : Ability() {
    private lateinit var viewModel: UserViewModel
    
    override fun onStart(intent: Intent) {
        super.onStart(intent)
        viewModel = UserViewModel(container.get())
        
        // 绑定视图和 ViewModel
        bindViewModel()
    }
    
    private fun bindViewModel() {
        // 处理 ViewModel 状态更新
        GlobalScope.launch {
            viewModel.user.collect { user ->
                updateUI(user)
            }
        }
    }
}

// 鸿蒙特定的数据持久化
class HarmonyOSDataStore(private val context: Context) {
    private val preferences = context.getSharedPreferences("app_data", Context.MODE_PRIVATE)
    
    fun saveData(key: String, value: String) {
        preferences.edit().putString(key, value).apply()
    }
    
    fun getData(key: String): String? {
        return preferences.getString(key, null)
    }
}

在这里插入图片描述

总结

应用架构是决定应用质量的关键因素。通过遵循最佳实践,我们可以构建可扩展、可测试和易于维护的应用。在 KMP 框架下,我们需要在共享代码中实现通用的架构模式,同时在各平台上适配特定的生命周期和 API。鸿蒙系统提供了完整的应用框架,使得跨平台架构实现相对平顺。关键是要选择合适的架构模式、遵循 SOLID 原则和进行充分的测试。

在工程实践中,可以重点思考:

  • 当前项目是否已经明确了分层边界和依赖方向?
  • 有多少业务逻辑可以迁移到 commonMain,从而减少多端重复?
  • 现有测试是否覆盖了关键用例,是否易于在多端回归?

建议的落地步骤:

  • 先在一个中等复杂度的业务模块上试点上述分层 + DI + 状态管理方案;
  • 逐步将成功经验推广到全局,并配合测试与性能优化策略;
  • 针对鸿蒙端梳理清晰的 UI 与 Ability 层边界,让共享业务层尽可能保持纯 Kotlin、可测试和可复用。
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐