zoukankan      html  css  js  c++  java
  • 策略模式与状态模式、命令模式

    策略模式与状态模式、命令模式

    三者的简介

    • 策略模式:定义一组算法,将每个算法都封装起来,并且使它们之间可以相互转换

    比如在执行一个排序算法的时候,排序的算turnOff冒泡、快排、堆排等,通过策略模式,则可以巧妙地在不同的算法之间进行切换。

    • 状态模式:当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类

    假设电视机有两种状态:开、关。如果电视机在开的时候,可以切换频道,电视机在关的时候,也可以切换频道。但是这两种切换频道所带来的结果不一样。

    • 命令模式:将一个请求封装成一个对象,从而让使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能

    主要是通过命令的发布者、命令、接收者,从而达到了发布者和接收者的解耦,并且能够更加精细的控制命令的执行状态。

    策略模式

    策略模式重在整个算法的替换,也就是策略的替换。

    通过注入不同的实现对象来实现算法或者策略的动态替换。模式的可扩展性、可维护性更高。

    策略模式中的行为是彼此独立的、可相互替换的。

    使用场景

    • 针对同一类型的多种处理方式,仅仅是具体行为有差别时。
    • 需要安全地封装多种同一类型的操作时。
    • 出现同一抽象类有多个子类,而又需要使用if-else或者switch-case来选择具体的子类时。

    UML图

    策略模式的UML图

    图片中

    • Context是上下文,用来操作策略模式的上下文
    • Stragety是一种策略的抽象
    • ConcreteStragetyA和B是具体的策略的抽象的实现

    总结

    由此可见,在策略模式中,最主要看重的东西是策略。对于一件事情可以有不同的策略,当然,策略的结果可以是一样的也可以是不一样的。一个问题如果有多个解决方案的时候,最简单的当然是利用if-else。但如果是对于方案特别多的时候,这样就会显得耦合性特别高,代码也会特别的臃肿。

    相对于if-else,策略模式将不同的策略构成一个具体的策略实现,通过不同的策略实现算法替换。

    举个例子,在Android中,存在一个动画的东西。而各种动画,则是使用了策略模式。所有的Android中的动画都是实现了Interpolator这个接口。

    状态模式

    状态模式的行为是平行的、不可替换的。

    状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。

    使用场景

    • 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为
    • 代码中包含大量与对象状态有关的条件语句

    电视机代码

    简述:

    电视机的状态有两种,一种是开一种是关,那么可以定义一个接口, 此时,对于两种状态,会有PowerOffState以及PowerOnState,如下

    interface TvState {
        fun nextChannel()
        fun prevChannel()
        fun turnOn()
        fun turnUp()
    }
    
    class PowerOffState : TvState {
        override fun nextChannel() {
            TODO("No action because of power off")
        }
        override fun prevChannel() {
            TODO("No action because of power off")
        }
        override fun turnUp() {
            TODO("No action because of power off")
        }
        override fun turnOn() {
            TODO("Can turn on")
        }
    }
    
    class PowerOnState : TvState {
        override fun nextChannel() {
            TODO("nextChannel")
        }
        override fun prevChannel() {
            TODO("prevChannel")
        }
        override fun turnUp() {
            TODO("Turn off")
        }
        override fun turnOn() {
            TODO("Do nothing because of power on")
        }
    }
    

    上述便是电视的状态,那么对于电视遥控器的状态呢?假设它只能够进行开或者关,那么有如下的代码:

    interface PowerController {
        fun powerOn()
        fun powerOff()
    }
    class TvController  : PowerController {
        private lateinit var tvState:TvState
        private fun setTvState(tvState:TvState){
            this.tvState=tvState
        }
        override fun powerOff() {
            setTvState(PowerOffState()) // 电视遥控器设置电视开机了
        }
        override fun powerOn() {
            setTvState(PowerOnState())  //电视遥控器设置电视关机了
        }
        fun nextChannel(){
            tvState.nextChannel() //电视遥控器设置下一个频道
        }
        fun prevChannel(){
            tvState.prevChannel()
        }
        fun turnUp(){
            tvState.turnUp()
        }
        fun turnDown(){
            tvState.turnDown()
        }
    }
    

    以上,就是状态模式中例子的代码。

    状态模式的UML图

    状态模式的UML图

    • State:抽象的状态类或者接口
    • ConcreteStateA、B是具体的状态类
    • Context是环境类

    总结

    举个例子,在Android中WiFi的开启,使用了状态模式。在WiFi初始状态下,扫描的请求直接被忽略,在驱动加载状态中WiFi扫描的请求直接被添加到延迟处理的消息列表中,在驱动加载完成后扫描的WiFi将会被直接处理。

    Android中的Wifi请求的行为表明了,在不同的状态下的不同行为,而这种模式就是状态模式。

    State模式将所有与一个特定的状态相关的行为都放入一个状态对象中,它提供了一个更好的方法来组织与特定状态相关的代码,将繁琐的状态判断转换成结构清晰的状态类族,在避免代码膨胀的同时也保证了可扩展性与可维护性。

    命令模式

    将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

    使用场景

    • 需要抽象出待执行的动作,然后以参数的形式提供出来。
    • 在不同的时刻制定、排列和执行请求。
    • 需要支持取消操作。
    • 需要支持事务操作。

    代码例子

    /**
     * 接收者类,一般该类是一个执行具体逻辑的角色
     */
    class Receiver {
        fun action() {
            TODO("Do something")
        }
    }
    
    /**
     * 抽象命令接口,命令角色
     */
    interface Command {
        fun execute()
    }
    
    /**
     * 具体命令类,
     */
    class ConcreteCommand(
        private var receiver: Receiver
    ) : Command {
        override fun execute() {
            receiver.action()
        }
    }
    
    /**
     * 请求者类
     */
    class Invoker(
        private var command:Command
    ){
        fun action(){
            command.execute()
        }
    }
    fun main(){
        val receiver=Receiver()
        val command=ConcreteCommand(receiver)
        val invoker=Invoker(command)
        invoker.action()
    }
    

    命令模式UML图

    命令模式UML图

    总结

    命令模式中,类非常的膨胀,大量衍生类的创建。好处是:更弱的耦合性、更灵活的控制性以及更好的扩展性。

    这是小睿的博客,如果需要转载,请标注出处啦~ヾ(≧▽≦*)o谢谢。
  • 相关阅读:
    linux 和 ubuntu 修改主机名
    Linux删除用户
    ubuntu更新源
    python连接mysql
    用于迭代器的yield return
    Tuple类型
    Action 和 Func
    用iDSDT制作声显卡DSDT
    C#“同步调用”、“异步调用”、“异步回调”
    读懂IL代码就这么简单
  • 原文地址:https://www.cnblogs.com/Yunrui-blogs/p/15189860.html
Copyright © 2011-2022 走看看