状态设计模式

本文详细介绍了状态模式的概念、原理及应用场景,通过电视遥控器的具体案例,展示了如何利用状态模式简化复杂的条件分支逻辑,提高代码的可读性和可维护性。

##状态模式 ###1.介绍:

状态模式中的行为由状态来决定,不同的状态有不同的行为。状态模式和策略模式的结构几乎一样,本质却完全不一样状态模式是平行的,不可替换的,策略模式的行为是彼此独立的,可相互替换。–状态模式对象的行为包装在不同的状态对象里,每个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象在其内部的状态改变的时候,其行为也发生变化。 ###2.状态模式的定义
当一个对象的内在状态改变时允许其改变行为,这个对象看起来像是改变了其类。 ###3.使用场景
1.一个对象的行为取决于ta的状态,并且ta必须在运行时根据状态改变ta的行为。
2.代码中包含大量与对象状态相关的条件判断语句,例如一个操作中包含庞大的多分支语句(if-else,swich-case),且这些分支依赖该对象的状态。
3.状态模式将每一个条件分支放入一个独立的类中,这使得你可以根据当前对象的情况将对象的状态看做一个对象,这一对象可以不依赖与其他对象而独立变化,这样通过多态来去除过多的,重复的if-else等分支语句
是不是很复杂,好的,那就继续搞事情
###4.UML类图

角色介绍
Context类,环境类,定义客户感兴趣的接口,维护一个State子类的实例,这个实例定义了对象的当前状态。
State:抽象状态类或者状态接口,定义一个或者一组接口,表示该状态下的行为。
ConcreteStateA,ConcreteStateB:具体状态类,每一个具体的状态类实现抽象,State的接口,从而达到不同状态下的不同行为。
###5.状态模式的简单实例

以电视遥控器为例来演示下状态模式的实现。首先将电视的状态简单分为开机状态和关机状态,在开机的状态下可以通过遥控器来进行频道切换,调整音量等操作,但是,此时重复开机键是无效的:而在关机状态下,频道切换,调整音量,关机都是无效的操作,只有按开机按钮时会生效。也就是电视的内部状态决定了遥控器的行为,下面是第一版的实现代码。
/**
* 电视遥控器,含有开机,关机,上一频道,下一频道,调高音量,调低音量的功能
*/
public class TvController {
//开机状态
private final static int POWER_ON = 1;
//关机状态
private final static int POWER_OFF = 2;
private int mState = POWER_OFF;
public void powerOn() {
mState = POWER_ON;
if (mState == POWER_OFF) {
System.out.println(“开机啦”);
}
}
public void powerOff() {
mState = POWER_OFF;
if (mState == POWER_ON) {
System.out.println(“关机啦”);
}
}
public void nextChannel() {
if (mState == POWER_ON) {
System.out.println(“下一频道”);
} else {
System.out.println(“两个红灯提示没有开机”);
}
}
public void preChannel() {
if (mState == POWER_ON) {
System.out.println(“上一频道”);
} else {
System.out.println(“两个红灯提示没有开机”);
}
}
public void turnUp() {
if (mState == POWER_ON) {
System.out.println(“调高音量”);
} else {
System.out.println(“两个红灯提示没有开机”);
}
}
public void turnDown() {
if (mState == POWER_ON) {
System.out.println(“调低音量”);
} else {
System.out.println(“两个红灯提示没有开机”);
}
}
}

  • 分析
  • 可以看到,在TvController类中通过mState字段中储存了电视的状态,并且在各个操作中根据状态来判断是否应该执行。
  • 这就导致了在每个功能中都需要用到if-else语句,代码重复,相对较为混乱当前还只是有两个状态,如果状态变为5个呢,10个呢?每个函数中都要用到if-else进行判断,而这些代码都充斥了一个类中,这些重复的代码无法被提取来,这就导致这个类变得愈发难以维护
  • 状态模式就是为了解决这类问题而出现的,我们将这些状态用对象来代替,用这些行为封装到对象中,使得在不同的状态下有不同的实现,这样就将这些if-else语句从TvController类中去掉,整个结构也变的清晰起来。接下来看看实现代码!
    /**
  • 电视状态接口的,定义了电视操作的函数
    */
    public interface TvState {
    public void nextChannel();
    public void preChannel();
    public void turnUp();
    public void turnDown();
    }

/**

  • 关机状态下,此时只有开机功能是有效的!
    */
    public class PowerOffState implements TvState {

    @Override
    public void nextChannel() {

    }

    @Override
    public void preChannel() {

    }

    @Override
    public void turnUp() {

    }

    @Override
    public void turnDown() {

    }
    }

/**

  • 开机状态下,此时再触发开机功能时不做任何操作!
    */
    public class PowerOnState implements TvState{
    @Override
    public void nextChannel() {
    System.out.println(“下一频道”);
    }

    @Override
    public void preChannel() {
    System.out.println(“上一频道”);
    }

    @Override
    public void turnUp() {
    System.out.println(“调高音量”);
    }

    @Override
    public void turnDown() {
    System.out.println(“调低音量”);
    }
    }

public interface PowerController {
public void powerOn();
public void powerOff();

}

public class TvController implements PowerController{
TvState mState ;
/**
* 关键代码
* @param mState
*/
public void setTvState(TvState mState) {
this.mState = mState;
}
@Override
public void powerOn() {
setTvState(new PowerOnState());
System.out.println(“开机啦”);
}
@Override
public void powerOff() {
setTvState(new PowerOffState());
System.out.println(“关机啦”);
}
//电视的操作代码族:
public void nextChannel() {
mState.nextChannel();
}
public void preChannel() {
mState.preChannel();
}
public void turnUp() {
mState.turnUp();
}
public void turnDown() {
mState.turnDown();
}
}

/**

  • 客户端代码
    */
    public class Client {

    public static void main(String[] args) {
    TvController tvController= new TvController();
    tvController.powerOn();
    tvController.nextChannel();
    tvController.turnUp();
    tvController.powerOff();
    tvController.turnUp();
    }
    }
    分析:
    上述实现中,我们抽象了一个TvState接口,该接口中有操作电视的所有函数,该接口中有两个实现类,即开机状态(PowerOnState)和(powerOffState)。开机状态下只有开机功能是无效的,也就是说在已开机状态,用户再按开机键不会发生什么反应;而在关机状态下,只有卡机功能是可用的,其他功能都不会生效。同一个操作,如调高音量turunUp函数,在关机状态下是无效的,在开机状态下就会将电视的音量调高,也就是说电视的内部状态以影响了电视遥控器的行为。
    状态模式将这些行为封装到状态类中,在进行操作时将这些功能转发给状态对象,不同的状态有不同的实现,这样就通过多态的形式去除了重复,杂乱的if-else语句,这也就正是状态模式的精髓所在。
    ###6.WIFI管理的状态模式

###7.状态模式实战

在开发过程中,我们用到状态模式最常见的地方应该是用户登录系统。在用户已登录和未登录的情况下,对于同一事件的处理行为是不一样的。未登录时点击转发按钮会先跳转到登录页面,然后在执行转发操作。如果已登录则用户可以输入转发内容后直接进行操作。可见在这两种状态下,对于转发这个操作的处理动画完全不一样。当状态改变时对于转发操作的行为发生了改变。
下面用状态模式来简单实现这个过程。首先在项目中有两个Activity,分别是Mainxx和Loginxx,Mainxx是应用的第一个Activity,有转发和注销用户的功能,Loginxx为登录页面。默认用户为未登录状态,此时用户在Mainxx界面点击转发时会先跳转到登录页面,然后在登录界面登录成功后再返回到Mainxx页面,此时用户再进行转发操作就可以实现真正的转发功能。
实例代码在这
https://github.com/WenPingkk/StatePattern/tree/master
###8.总结

状态模式的关键点在于不同的状态下对于同一行为有不同的响应,这其实就是一个将if-else用多态来实现的一个具体实例。在if-else,switch-case形式下根据不同的状态进行判断,如果是状态A则执行状态A的方法,反之则执行其他对应状态的方法,if-else的这种实现使得业务逻辑都耦合在一起,易于出错,通过状态模式能够很好的消除这类“丑陋”的逻辑处理,当然这不是任何出现if-else的地方都应该用状态模式来重构,应在符合特定的场景下才建议使用对应的模式。
优点:State模式将所有与一个特定的状态相关的行为都放入一个状态对象中,它提供了一个更好的方法来组织和特定状态相关的代码,将繁琐的状态判断转换成结构清晰的状态类族,在避免代码膨胀的同时也保证了可拓展性和课维护性。
缺点:状态模式的使用必然会增加系统类和对象的个数!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值