状态模式State
状态切换
当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化
把各种判断逻辑分布到State的子类之间,来减少相互间的依赖
Context:环境类,持有对State的引用,实际上拥有状态的对象。
State:抽象状态类,封装与Contex的一个特定状态的行为
ConcreteState 每个类实现了状态具体行为
把各种状态及实现封装成一个ConcreteState,通过Context来操作他们之间的自动状态跳转
切换方式:
1.环境类同时是状态管理器(State Manager),负责状态之间的切换。在环境类的changeState方法中对某些属性做出判断,从而做出相应的转换
2.具体状态类负责状态转换,判断放在其内部
使用场景
某个类的核心状态是易变的,当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时
当控制一个对象状态转换的条件表达式过于复杂时的情况,,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化
条件表达式一定要是“开关切换状态”,才可以使用State模式,即是根据自身当前状态,会做出不同的行为,这些状态还会在不同的条件下相互转换
开关切换状态:状态本身做为一个判断条件
public class DiffTest {
public static void main(String[] args) {
Light light = new Light();
light.state = "开";
// 状态模式 开关切换状态,自身参与到条件判断中
if( light.state.equals("开")){
light.state = "关";
}else if (light.state.equals("关")){
light.state = "开";
}
// 策略模式 一般状态判断
String OtherConditions = "天黑";
if ( OtherConditions.equals("天黑")){
light.state = "开";
}else if (OtherConditions.equals("天亮") ){
light.state = "关";
}
}
}
class Light{
public String state;
}
与策略模式的区别:
在状态模式中,状态的变迁是由对象的内部条件决定,外界只需关心其接口,不必关心其状态对象的创建和转化;而策略模式里,采取何种策略由外部条件决定。
策略模式的各种策略(具体实现类)是平级的,比如早饭我可以选择吃粥或油条或鸡蛋,我能选择我要吃什么
状态模式的各种状态却不是平级的,而是具有某种转化关系的,即状态迁移,比如水在0度以下会结冰,过了零度会升温.
状态转换场景中,最好不要由客户端来直接改变状态(也不是绝对不可以),而是客户端做了某种其它操作引起状态迁移,也就是说客户端最好不要直接创建一个具体 State 实现类的实例对象,通过 setState() 方法来设置。状态转化也可能是其内部的某些行为造成的
从代码上理解差异:是谁促使了行为的改变
状态模式中,状态转移由 Context 或 State 自己管理。如果你在State中管理状态转移,那么它必须持有Context的引用,在State内部使用Context.SetState()
而策略模式中,Strategy 从不持有Context的引用,是客户端把所选择的 Strategy 传递给Context。
这篇文章讲的很好
实例
银行余额,大于0正常使用,小于0大于-2000限制使用,低于-2000禁止使用
以下实现由ConcreteState管理状态迁移
State:
账户状态:
public interface AccountState {
void ShowMoney(AccountContext ac);
}
ConcreteState:
正常下状态,低于0时自动转入下一状态
public class NormalState implements AccountState {
@Override
public void ShowMoney(AccountContext accountContext) {
if (accountContext.getMoney()>0){
System.out.println("正常使用");
}
else {
accountContext.setState(new LimitState());
accountContext.show();
}
}
}
限制状态:
低于-2000自动转入下一状态
public class LimitState implements AccountState {
@Override
public void ShowMoney(AccountContext accountContext) {
if (accountContext.getMoney()>-2000){
System.out.println("限制使用");
}
else{
accountContext.setState(new BanState());
accountContext.show();
}
}
}
禁止状态
当前最后的状态,无需再向下进行状态迁移了
public class BanState implements AccountState {
@Override
public void ShowMoney(AccountContext accountContext) {
System.out.println("拒绝使用");
}
}
Context环境类:
public class AccountContext {
private double money;
private AccountState state;
public AccountContext(){
state = new NormalState();
}
public void setMoney(double money) {
this.money = money;
}
public double getMoney() {
return money;
}
public void setState(AccountState state) {
this.state = state;
}
public void show(){
state.ShowMoney(this);
}
}
测试:
public class Test {
public static void main(String[] args) {
AccountContext ac = new AccountContext();
ac.setMoney(-3000);
ac.show();
}
}
输出:拒绝使用
根据设置的金额,状态从由正常->限制->禁止,自动转化,最后调用禁止的showmoney