观心静

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

前言

  密封类是 Kotlin 中表达受限类层次结构的强大工具,能够提供更好的类型安全和更清晰的代码结构。

运用场景

  1. 状态管理(如 UI 状态、网络请求结果)
  2. 表达式树(如编译器中的 AST 节点)
  3. 命令模式中的命令类型
  4. 事件处理系统中的不同事件类型

 

假设有国内和国外两个登入仓库类需要运用密封类封装

实际上需要使用到继承,虽然和正常继承看起来没什么区别,但是意义是密封类限制了子类。 否则正常继承类谁都可以到处继承


import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

//登入密封类
sealed class LoginRepository {

    abstract suspend fun login(username: String, password: String): LoginResult

    //国内的登入仓库类
    class DomesticRepository : LoginRepository() {
        private val apiService = DomesticLoginApi()

        override suspend fun login(username: String, password: String): LoginResult {
            return try {
                val response = apiService.loginWithPhone(username, password)
                if (response.success) {
                    LoginResult.Success(response.userData)
                } else {
                    LoginResult.Fail(-1, response.errorCode)
                }
            } catch (e: Exception) {
                LoginResult.Fail(-1, e.message?:"")
            }
        }
    }
    //国外的登入仓库类
    class OverseasRepository : LoginRepository() {
        private val apiService = OverseasLoginApi()

        override suspend fun login(username: String, password: String): LoginResult {
            return try {
                val response = apiService.loginWithEmail(username, password)
                if (response.ok) {
                    LoginResult.Success(response.userData)
                } else {
                    LoginResult.Fail(-1, response.errorMessage)
                }
            } catch (e: Exception) {
                LoginResult.Fail(-1, e.message?:"")
            }
        }
    }
}

// 假设的API服务类
class DomesticLoginApi {
    suspend fun loginWithPhone(phone: String, smsCode: String): DomesticLoginResponse {
        // 调用国内登录API实现
        delay(1000)
        return DomesticLoginResponse(true, UserData("user123"), errorCode = "")
    }
}

class OverseasLoginApi {
    suspend fun loginWithEmail(email: String, password: String): OverseasLoginResponse {
        // 调用国外登录API实现
        delay(1000)
        return OverseasLoginResponse(true, UserData("user456"), "")
    }
}

// 辅助类和工厂
data class UserData(val id: String)

class DomesticLoginResponse(
    val success: Boolean,
    val userData: UserData,
    val errorCode: String
)

class OverseasLoginResponse(
    val ok: Boolean,
    val userData: UserData,
    val errorMessage: String
)

//登入返回结果的密封类
sealed class LoginResult {
    data class Success(val userData: UserData) : LoginResult()
    data class Fail(val code:Int,val message: String) : LoginResult()
}

//viewModel工厂类
class LoginViewModelFactory(private val repository: LoginRepository) : ViewModelProvider.Factory {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return LoginViewModel(repository) as T
    }
}

//viewModel选择依赖注入仓库类的方式
class LoginViewModel(private val repository: LoginRepository) : ViewModel() {
    private val _loginState = MutableStateFlow<LoginResult?>(null)
    val loginState = _loginState.asStateFlow()

    fun performLogin(username: String, password: String) {
        viewModelScope.launch {
            _loginState.value = repository.login(username, password)
        }
    }
}

class LoginActivity : AppCompatActivity() {
    private lateinit var viewModel: LoginViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //上面view相关代码略掉...
        
        
        //这里是关键!!! 根据情况选择国内还是国外登录仓库,这里假设选择了国内登录
        var isDomestic = true
        val repository = if(isDomestic){
            LoginRepository.DomesticRepository()
        } else {
            LoginRepository.OverseasRepository()
        }

        viewModel = ViewModelProvider(this, LoginViewModelFactory(repository))
            .get(LoginViewModel::class.java)

        lifecycleScope.launch {
            viewModel.loginState.collect { result ->
                when (result) {
                    is LoginResult.Success -> {
                        // 处理登录成功
                    }
                    is LoginResult.Fail -> {
                        // 处理登录失败
                    }
                    null -> Unit
                }
            }
        }
        
        //模拟点击登入
        binding.loginButton.setOnClickListener {
            val username = binding.usernameEditText.text.toString()
            val password = binding.passwordEditText.text.toString()
            viewModel.performLogin(username, password)
        }
    }
}

 

 

在网络请求返回时的运用

密封网络请求结果

sealed class HttpResult {
    data class Success<out T>(val data: T) : HttpResult()
    data class Error(val code: Int, val message: String) : HttpResult()
}

在仓库层组装

/**
 * 注册
 * @param account 账号
 * @param password 密码
 */
fun register(account: String, password: String):HttpResult{
    try {
        val params = mapOf(
            "accountNo" to account,
            "password" to password
        )
        val response = http.register(params)
        if(!response.isSuccessful){
            return HttpResult.Error(-1, response.message())
        }
        val res = response.body()
        if (res?.code == 200){
            return HttpResult.Success(res.data)
        }
        return HttpResult.Error(res?.code?:-1, res?.msg?:"")
    } catch (e: Exception) {
        e.descriptionError().logE()
        return HttpResult.Error(-1, e.descriptionError())
    }
}

使用的时候

    val res = AccountRepository().register("1","1")
        when(res){
            is HttpResult.Success<*> -> {
                res.data
                println("成功")
            }
            is HttpResult.Error -> {
                res.message
                println("失败")
            }
        }

 

 

 

 

 

end

posted on 2025-08-07 10:44  观心静  阅读(71)  评论(0)    收藏  举报