[即学即用] Android开发——状态模式

前言

相信 “大多数” 伙伴看了相关设计模式书籍、文章,一看就会,一写就 ***
在实际开发中也很少用上,或者说不知道在哪用,缺少应用场景,久而久之就忘记了~

在这篇文章中,我分享一下,我在Android 开发中使用到到设计模式——状态模式,希望大家喜欢~

需求

假设我们有这样一个需求 (文章类 App)

当用户点击头像的时候

  • 未登录状态:点击头像,则跳转到 登录页面在进行登录
  • 登录状态:点击头像,则不采取任何操作

编码

接到需求后,这不是so easy 吗?一顿霹雳吧啦敲代码

class MainActivity :AppCompatActivity(){

    private val isLogin: Boolean by Preference("isLogin", false)

    ...省略部分代码

    override fun initView() {

        // 点击头像
        mIvPortrait.setOnClickListener {
            if (isLogin) {
                startActivity<LoginActivity>()
            }
        }
    }

    ...省略部分代码
}

Preference 封装了 SharedPreferences ,Kotlin 的委托语法,不是本文重点,这里就不过多介绍了,如有不了解的小伙伴,可以私下百度学习~

通过 SharedPreferences 保存一个 用户是否登录(isLogin) boolean 变量,然后根据该变量,来判断是否进行登录页面跳转。

逻辑相对简单,暂时看起来没啥问题, 接下来我们在进一步看看扩展需求

扩展需求

当用户点击文章收藏的时候

  • 未登录状态:点击收藏,则跳转到 登录页面在进行登录
  • 登录状态:点击收藏,则发起收藏请求,文章进行收藏

编码

class MainActivity :AppCompatActivity(){

    private val isLogin: Boolean by Preference("isLogin", false)

    ...省略部分代码

    override fun initView() {

        // 点击头像
        mIvPortrait.setOnClickListener {
            if (isLogin) {
                startActivity<LoginActivity>()
            }
        }
        
        // 点击收藏按钮
        mBtnCollect.setOnClickListener {
            if (isLogin) {
                viewModel.collect(articleId)
            } else {
                startActivity<LoginActivity>()
            }
        }
    }

    ...省略部分代码
}

同理,我们在 点击收藏按钮处理逻辑上,也是根据 isLogin变量,来进行判断是否收藏,再进行相应逻辑处理。这里我们可以嗅得到代码的坏味道,重复的 登录状态 判断。

若我们在增加一个 当用户点击分享按钮进行文章分享,我们再次添加判断逻辑,如下代码:

// 点击收藏按钮
mBtnShare.setOnClickListener {
    if (isLogin) {
        viewModel.share(articleId)
    } else {
        startActivity<LoginActivity>()
    }
}

这样在我们 Android 项目中,会充满大量 登录逻辑判断,这样代码的质量大打折扣,不利于后续开发维护

思考

如果是你,你会怎么做?

当然是 CV 代码,又不是不能用 :)

若CV 代码,那么你肯定会给同事/大佬口吐芬芳: ***

废话不多说,进入正文,设计模式——状态模式

状态模式

介绍:状态模式中的行为是由状态来决定的,不同的状态下有不同的行为。
定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变来其类。

就如上文所说,当用户登录状态下,会有收藏点赞分享等操作行为。
若用户没有登录,则需要跳转到 登录页面进行 登录,才可以进行后续操作。

而这个用户状态的改变(未登录-> 登录),是在一个对象内部的,外在是无感知的。但实际行为应 状态的改变而改变。

说起来可能有点绕哈。我们来看看实际代码演示

UserState

interface UserState {

    fun collect(context: Context?, block: () -> Unit)
    
    fun share(context: Context?, block: () -> Unit)

    fun login(context: Context?)
}

我们先创建一个 UserState 接口类,结合上面背景,这里定义 logincollectshare 方法
(行为),然后我们分别创建 登录状态(LoginState) 类,未登录状态(LogoutState)类,并实现 UserState 接口

LoginState

class LoginState : UserState {

    override fun collect(context: Context?, block: () -> Unit) {
        // 发起收藏
        block()
    }
    
    override fun share(context: Context?, block: () -> Unit) {
        // 发起分享
        block()
    }

    // 已登录状态 无须登录 不做任何操作
    override fun login(context: Context?) {}
}

在登录状态下,我们执行相应的逻辑操作,登录状态下,无须登录,所以这里不做任何操作

LogoutState

class LoginState : UserState {

    // 收藏
    override fun collect(context: Context?, block: () -> Unit) {
        goLoginActivity(context)
    }
    
    // 分享
    override fun share(context: Context?, block: () -> Unit) {
        goLoginActivity(context)
    }

    // 登录
    override fun login(context: Context?) {
        goLoginActivity(context)
    }
    
    // 跳转到登录
    private fun goLoginActivity(context: Context?) {
        context?.run {
            toast(getString(R.string.please_login))
            startActivity<LoginActivity>()
        }
    }
}

这里相信大家也已经猜到,未登录状态下,统一跳转到 登录页面进行登录,在进行后续操作

然后我们在定一个 管理状态的类 UserContext,方便管理我们的用户状态

UserContext

object UserContext{

    // 持久化存储 登录状态
    private var isLogin: Boolean by Preference(Key.LOGIN, false)

    // 设置默认状态
    var mState: UserState = if (isLogin) LoginState() else LogoutState()

    // 收藏
    fun collect(context: Context?, block: () -> Unit) {
        mState.collect(context, block)
    }
    
     // 分享
    fun share(context: Context?, block: () -> Unit) {
        mState.share(context, block)
    }

    // 登录
    fun login(context: Activity?) {
        mState.login(context)
    }
    
    // 切换成 登录状态
    fun setLoginState(){
        // 改变 sharedPreferences   isLogin值
        isLogin = true
        mState = LoginState()
    }
    
    // 切换成 未登录状态
    fun setLogoutState(){
        // 改变 sharedPreferences   isLogin值
        isLogin = false
        mState = LogoutState()
    }
}

UserContext管理着 用户的状态,mState 变量默认初始化为 未登录状态,并声明切换登录状态未登录状态切换的方法,方便后续切换状态使用,最后回到 MainActivity中,我们来看看 实际如何使用。

MainActivity

class MainActivity :AppCompatActivity(){

    //private val isLogin: Boolean by Preference("isLogin", false)

    ...省略部分代码

    override fun initView() {

        // 点击头像
        mIvPortrait.setOnClickListener {
            // 调用 登录
            UserContext.login(this) 
        }
        
        // 点击收藏按钮
        mBtnCollect.setOnClickListener {
            // 调用 收藏
            UserContext.collect(this) {
                viewModel.collect(articleId)
            }
        }
        
        mBtnShare.setOnClickListener {
            // 调用 分享
            UserContext.share(this) {
                viewModel.share(articleId)
            }
        }
    }

    ...省略部分代码
}

在 MainActivity中,我们可以优雅实现登录收藏分享功能,在也不用 if-else 判断。

至于切换状态,在登录成功回调中,或者是 退出登录中,可以调用 UserContext 进行状态切换即可。是如下代码:

// 点击退出登录 按钮
mBtnLogout.setOnClickListener {
    // 设置当前状态 为 未登录状态
    UserContext.setLogoutState()
}
// 登录成功 回调
private fun loginSuccess() {
    // 设置当前状态为  登录状态
    UserContext.setLoginState()
}

切换了状态,对于 MainActivity 而言,无需做任何修改,但其里面的行为却发生了变化。

最后

至此,这是一个完整的状态模式实现,从一开始没有使用设计模式,代码中充满了 if-else 的逻辑判断,缺少美感,到后面使用设计模式,前后对比,虽然 类有所增加类 ,但是把烦琐的状态,转换成结构清晰的状态类族,从而避免重复代码,也保证了可扩展性和可维护性,用心感受——状态模式 的魅力吧~

还不赶紧用起来? :)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值