欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式与应用:状态模式

程序员文章站 2022-06-17 17:09:18
...

本文主要介绍状态模式的原理和应用场景,并与策略模式、责任链模式进行对比

简介

State模式也叫状态模式,是行为设计模式的一种。

State模式允许通过改变对象的内部状态而改变对象的行为,这个对象表现的就好像修改了他的类一样。

状态模式的应用场景

主要解决:当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转译到表现不同状态的一系列类当中,可以把复杂的判断逻辑简化。

结构图

设计模式与应用:状态模式

角色和职责

  • Context 用户对象。拥有State类型的成员,以标识对象的当前状态
  • State 接口或基类。封装与Context的特定状态相关的行为
  • ConcreteState 接口实现类或子类,实现了一个与Context某个状态相关的行为

实现

设计模式与应用:状态模式

状态作用对象

package com.mym.designmodel.State;

/**
 * 职责:Context 用户对象。拥有State类型的成员,以标识对象的当前状态
 */
public class Worker {

    private State state;

    private int hour;

    public Worker(){
        state = new AMState();
    }

    public int getHour() {
        return hour;
    }

    public void setHour(int hour) {
        this.hour = hour;
    }

    public void setState(State state) {
        this.state = state;
    }

    public State getState() {
        return state;
    }

    public void doWork(){
        state.doWorker(this);
        state = new AMState();//复原状态。当状态走到最后时复原到最初状态
    }
}

抽象状态

package com.mym.designmodel.State;

/**
 * 职责:State 接口或基类。封装与Context的特定状态相关的行为
 */
public abstract class State {
    public abstract void doWorker(Worker worker);
}

具体各个状态:上午状态

package com.mym.designmodel.State;

/**
 * 职责:ConcreteState 接口实现类或子类,实现了一个与Context某个状态相关的行为
 */
public class AMState extends State {
    @Override
    public void doWorker(Worker worker) {
        if(worker.getHour() == 9){
            System.out.println("做上午的事情!");
        }else{
            worker.setState(new PMState());
            worker.doWork();
        }
    }
}

具体各个状态:下午状态

package com.mym.designmodel.State;

/**
 * 职责:ConcreteState 接口实现类或子类,实现了一个与Context某个状态相关的行为
 */
public class PMState extends State {
    @Override
    public void doWorker(Worker worker) {
        if(worker.getHour() == 15){
            System.out.println("做下午的事情!");
        }else{
            worker.setState(new NightState());
            worker.doWork();
        }
    }
}

具体各个状态:晚上状态

package com.mym.designmodel.State;

/**
 * 职责:ConcreteState 接口实现类或子类,实现了一个与Context某个状态相关的行为
 */
public class NightState extends State {
    @Override
    public void doWorker(Worker worker) {
        if(worker.getHour() == 20){
            System.out.println("做晚上的事情!");
        }else{
            worker.setState(new NoState());
            worker.doWork();
        }
    }
}

具体各个状态:未定义状态

package com.mym.designmodel.State;

/**
 * 职责:ConcreteState 接口实现类或子类,实现了一个与Context某个状态相关的行为
 */
public class NoState extends State {
    @Override
    public void doWorker(Worker worker) {
        System.out.println(worker.getHour()+":未定义该做什么事情!");
    }
}

测试

package com.mym.designmodel.State;

/**
 * 测试
 */
public class MainClass {
    public static void main(String[] args) {
        Worker worker = new Worker();
        worker.setHour(9);
        worker.doWork();

        worker.setHour(15);
        worker.doWork();

        worker.setHour(20);
        worker.doWork();

        worker.setHour(23);
        worker.doWork();

        //这里测试复原,如果状态没有复原,这里将是未定义状态
        worker.setHour(9);
        worker.doWork();
    }
}

结果:

做上午的事情!
做下午的事情!
做晚上的事情!
23:未定义该做什么事情!
做上午的事情!

需要注意的是状态的复位。如果Worker最后一个状态执行完后,没有复位那么接下来该Worker都处于最后一个状态。执行结果就如下:

做上午的事情!
做下午的事情!
做晚上的事情!
23:未定义该做什么事情!
9:未定义该做什么事情!

状态模式思考于策略模式、责任链模式

状态模式和策略模式实际上都是根据不同条件执行不同事情。但是:

  • 状态模式更加关注的是类内部状态迁移,对外(客户端)不可见,客户端只需要按照既定的执行流程调用即可
  • 策略模式更加关注的是外部主动选择执行流程。

状态模式之于责任链模式,可能觉得这状态迁移很像责任链链式的执行。但是:

  • 状态模式每个状态都是同等层次,没有执行体的上下游
  • 责任链模式每个节点都是有执行先后顺序,关注的是整体共同完成一件事。