前言
密封类是 Kotlin 中表达受限类层次结构的强大工具,能够提供更好的类型安全和更清晰的代码结构。
运用场景
- 状态管理(如 UI 状态、网络请求结果)
- 表达式树(如编译器中的 AST 节点)
- 命令模式中的命令类型
- 事件处理系统中的不同事件类型
假设有国内和国外两个登入仓库类需要运用密封类封装
实际上需要使用到继承,虽然和正常继承看起来没什么区别,但是意义是密封类限制了子类。 否则正常继承类谁都可以到处继承
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
本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/19026292
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。