# 七大软件规划原则
# 规划形式-工厂形式
# 规划形式-单例形式
# 规划形式-原型形式
# 规划形式-战略形式
# 规划形式-职责链形式
# 规划形式-制作者形式
# 规划形式-深度剖析代理形式
# 规划形式-门面形式
# 规划形式-装修器形式
# 规划形式-享元形式
# 规划形式-组合形式
# 规划形式-适配器形式
# 规划形式-桥接形式
# 规划形式-委派形式
# 规划形式-模板办法形式
# 规划形式-迭代器形式
# 规划形式-命令形式 # 规划形式-备忘录形式

状况形式(State Pattern )也称为状况机形式(State Machine Pattern),是允许目标在内 部状况产生改动时改动它的行为,目标看起来如同修改了它的类,归于行为型形式。

状况形式中类的行为是由状况决定的,不同的状况下有不同的行为。其意图是让一个目标在 其内部改动的时候,其行为也随之改动。状况形式核心是状况与行为绑定,不同的状况对应不同的行为。

适用场景

  1. 行为随状况改动而改动的场景
  2. 一个操作中含有庞大的多分支结构,而且这些分支取决于目标的状况

简略来说状况形式主要解决的便是当控制一个目标状况的条件表达式过于杂乱时的情况。通过把状况 的判别逻辑转移到表明不同状况的一系列类中,能够把杂乱的判别逻辑简化。目标的行为依赖 于它的状况(特点),而且会依据它的状况改动而改动它的相关行为。

好处是客户端只需求调用自己需求的操作即可。

UML类图

设计模式-状态模式

详细代码如下:

public interface IState {
    void handle();
}
public class ConcreteStateA implements IState{
    @Override
    public void handle() {
        System.out.println("状况A下的操作");
    }
}
public class ConcreteStateB implements IState{
    @Override
    public void handle() {
        System.out.println("状况B下的操作");
    }
}
public class Context {
    private IState state;
    private final IState STATE_A = new ConcreteStateA();
    private final IState STATE_B = new ConcreteStateB();
    {
        state = STATE_A;
    }
    public void setState(IState state) {
        this.state = state;
    }
    public void handle(){
        state.handle();
        //下一次调用变成状况B调用
        setState(STATE_B);
    }
}
public class Test {
    public static void main(String[] args) {
        Context context = new Context();
        context.handle();
    }
}

代码示例

举个验证码登录的例子,假定咱们在规划咱们的系统登录功能,首要必定不能让用户一直不停的获取短信然后登录吧,如果是这样那么光这个短信费就能把公司搞死了,所以一般是这样规划的,一天只能有几回获取登录短信的时机用完了只能等到明日在获取(当然更精密的需求或许是短时间内有几回时机用完过两三个小时在给几回时机在用完就等到第二天,这儿咱们仅仅做一个demo没必要搞那么费事),这个时候咱们就能够提取出来两个状况,一个是正常获取短信验证码的状况、第二个便是获取短信验证码次数达到上线这两种状况。

首要先把状况的抽象类提取出来如下:

public interface ISmsState {
    Integer getSmsCode();
}

然后分别实现两种状况:

public class NormalSmsState implements ISmsState {
    @Override
    public Integer getSmsCode() {
        return (int) (Math.random()*9000+1000);
    }
}
public class AbnormalSmsState implements ISmsState{
    @Override
    public Integer getSmsCode() {
        System.out.println("获取验证码的次数已达到上线");
        return null;
    }
}

创立环境类人物

public class SmsManager {
    private ISmsState state;
    private final HashMap<Integer,Integer> userCount = new HashMap<>();
    private final ISmsState NORMAL = new NormalSmsState();
    private final ISmsState ABNORMAL = new AbnormalSmsState();
    public Integer getSmsCode(Integer userId) {
        if(userCount.containsKey(userId)){
            if(userCount.get(userId) >= 5){
                state = ABNORMAL;
            }else{
                state = NORMAL;
            }
            userCount.put(userId,userCount.get(userId) + 1);
        }else{
            state = NORMAL;
            userCount.put(userId,1);
        }
        return state.getSmsCode();
    }
}

客户端调用

public class Test {
    public static void main(String[] args) {
        SmsManager sms = new SmsManager();
        for (int i = 0; i < 7; i++) {
            System.out.println(sms.getSmsCode(1111));
        }
    }
}

设计模式-状态模式

从上面的示例能够看出,状况的转化基本上都是内部行为,主要在状况形式内部来保护。比方关于要登录的人员,任何时候他的操作都是获取验证码,可是获取验证码管理目标的处理却不一定相同,会依据用户获取的次数来判别状况,然后依据状况去挑选不同的处理。

状况形式和战略形式以及职责链形式的差异

首要是状况形式和职责链形式,职责链是不知道自己下一个处理目标是谁的,职责链的联调是客户端去链接的,而状况形式,自己是知道下一个状况是什么的。

状况形式和战略形式的差异,其实上文中的例子或许我们看到都会觉得这不便是战略形式吗,只能说能够运用战略形式实现,他们有一个最大的差异是战略形式只能挑一种算法去实现(用户去挑选其中一种)而且每个算法之间是没有相互关系的,而状况形式各个状况之间是有某种联系的而且用户是不能去指定状况的,只能是初始化状况

状况形式的优缺点

长处:

  1. 结构明晰:将状况独立为类,消除了客户端冗余的if…else 或 switch..case 句子,使代码愈加简洁, 提高系统可保护性;
  2. 将状况转化显示化:通常的目标内部都是运用数值类型来定义状况,状况的切换是通过赋值 进行表现,不行直观;而运用状况类,在切换状况时,是以不同的类进行表明,转化意图愈加 清晰;
  3. 状况类职责清晰且具备扩展性。

缺点:

  1. 类数量添加结构变得更杂乱
  2. 开闭原则的支撑欠好如果需求添加一个状况或许削减一个状况必定是要改对应的办法的