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

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

三者的简介

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

比如在执行一个排序算法的时候,排序的算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图

总结

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

posted @ 2021-08-26 15:30  野生的Lemon柠檬  阅读(619)  评论(0编辑  收藏  举报

呱呱呱呱呱🐸