美文网首页
Kotlin写状态模式的一个实例

Kotlin写状态模式的一个实例

作者: 超级绿茶 | 来源:发表于2020-09-11 11:19 被阅读0次

当对象具有多种行为且这些行为的改变由不同的状态决定,称之为状态模式。这个定义不知你懂不懂,反正我当时是很懵逼的。所以我打算用一个实例来说明一下;

首先有这么个需求:游客、用户、管理员三种身份,当这三种身份在遇到收藏、分享、编辑、删除时会怎么样?

  • 游客就是未登录状态,所以遇到所有的操作都是一律跳跳登录。
  • 用户就是登录状态,可以收藏、分享但不能编辑和删除。
  • 管理员的功能只能编辑和删除。

但我们要怎么写代码呢?

val userState = getUserState()
btnCollect.setOnClickListener {
    when (userState) {
        "guest" -> gotoLogin()
        "normal" -> onCollect()
        "admin" -> alert("你没有这个权限")
    }
}

btnShare.setOnClickListener {
    when (userState) {
        "guest" -> gotoLogin()
        "normal" -> onShare()
        "admin" -> alert("你没有这个权限")
    }
}

btnEdit.setOnClickListener {
    when (userState) {
        "guest" -> gotoLogin()
        "normal" -> alert("你没有这个权限")
        "admin" -> onEdit()
    }
}

btnDelete.setOnClickListener {
    when (userState) {
        "guest" -> gotoLogin()
        "normal" -> alert("你没有这个权限")
        "admin" -> onDelete()
    }
}

不用我多解释,你一定看得懂上面的代码的意思。那有看出什么问题了吗?
每个方法内的分支太多,而且分支的条件是相同的,试想下如果以后要再多一个用户身份时会怎么样?每个方法就要再多加一条分支判断,可能你会觉得不算什么麻烦的事,但往往在实际开发中的需求可能比这个更复杂,从而使代码变得更凌乱。

那我们今天的目的就是用状态模式来改写这段代码。首先我们需要把用户的行为抽象出来统一管理,再根据身份不同的选择不同的对象行为。具体步骤如下:

  1. 把所以有的用户行为定义到个用户接口文件中。
  2. 声明三个代表不同身份的类,并继承用户接口。
  3. 生成一个用户身份管理类,根据身份的不同提供不同的对象。
/**
 * 定义用户接口,将不同身份的用户功能集中在此
 */
interface IUserFun {
    fun onCollect(block: () -> Unit)
    fun onShare(block: () -> Unit)
    fun onEdit(block: () -> Unit)
    fun onDelete(block: () -> Unit)
}

然后我们在创建三个代表不同身份的用户类,并继承这个接口

/**
 * 游客:用户做任何操作都只会跞登录界面
 */
class Guest : IUserFun {
    override fun onCollect(block: () -> Unit) {
        gotoLogin()
    }

    override fun onShare(block: () -> Unit) {
        gotoLogin()
    }

    override fun onEdit(block: () -> Unit) {
        gotoLogin()
    }

    override fun onDelete(block: () -> Unit) {
        gotoLogin()
    }

    fun gotoLogin() {
        // 跳用户登录界面
    }
}

/**
 * 普通用户:不可以编辑和删除,但能收藏和分享
 */
class Normal : IUserFun {
    override fun onCollect(block: () -> Unit) {
        block()
    }

    override fun onShare(block: () -> Unit) {
        block()
    }

    override fun onEdit(block: () -> Unit) {
        Log.w("test", "你没有这个权限")
    }

    override fun onDelete(block: () -> Unit) {
        Log.w("test", "你没有这个权限")
    }
}

/**
 * 管理员权限:可能编辑和删除
 */
class Admin : IUserFun {
    override fun onCollect(block: () -> Unit) {
        Log.w("test", "管理员不能做这个操作")
    }

    override fun onShare(block: () -> Unit) {
        Log.w("test", "管理员不能做这个操作")
    }

    override fun onEdit(block: () -> Unit) {
        block()
    }

    override fun onDelete(block: () -> Unit) {
        block()
    }
}

现在我们需要实现个一用户管理类,这个类会有单例模式运行。可以把这个类理解成MVP的P层,通过这个类向视图层提供功能实现。当用户身份改变时向视图层提供的不同的逻辑,但方法不变。

/**
 * 用户管理类
 */
object UserManager {

    var user: IUserFun = Guest()

    /**
     * 根据不同的身份返回不同的用户类
     */
    fun setUserState(userState: String) =
        when (userState) {
            "guest" -> Guest()
            "normal" -> Normal()
            "admin" -> Admin()
            else -> Guest()
        }

    fun collect(block: () -> Unit) {
        user.onCollect(block)
    }

    fun share(block: () -> Unit) {
        user.onShare(block)
    }

    fun edit(block: () -> Unit) {
        user.onEdit(block)
    }

    fun delete(block: () -> Unit) {
        user.onDelete(block)
    }
}

最后看一下是怎么调用的

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btnCollect.setOnClickListener {
            UserManager.collect {
                // 在这里实现收藏的具体业务逻辑
            }
        }
        btnShare.setOnClickListener {
            UserManager.share {
                // 在这里实现分享的具体业务逻辑
            }
        }
        btnEdit.setOnClickListener {
            UserManager.edit {
                // 在这里实现编辑的具体业务逻辑
            }
        }
        btnDelete.setOnClickListener {
            UserManager.delete {
                // 在这里实现删除的具体业务逻辑
            }
        }
    }

    override fun onStart() {
        super.onStart()
        val userState = requestUserState() // 假设从网络接口获取到用户的身份
        UserManager.setUserState(userState) // 更改用户的身份
    }

因为调用是发生在视图层的,而那些用户功能在实际开发中也需要用到视图的一些属性,所以利用Kotlin的函数式表达式可以把用户功能相关的代码滞后到用户调用的时候给出。

状态模式就说到这里,如果你还是很懵逼的话就再多看几遍,看看我们调用的地方是不是少了之前的when分支?可以从调用的地方往回看,要看不懂的话还可以聊私我。

欢迎加入QQ群聊【口袋里的安卓】或关注同名的微信公众号

相关文章

网友评论

      本文标题:Kotlin写状态模式的一个实例

      本文链接:https://www.haomeiwen.com/subject/fnvvektx.html