设计模式系列—状态模式

开发 前端
本篇和大家一起来学习状态模式相关内容。

 模式定义

对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

状态模式把受环境改变的对象行为包装在不同的状态对象里,其意图是让一个对象在其内部状态改变的时候,其行为也随之改变。现在我们来分析其基本结构和实现方法。

模板实现如下:

package com.niuh.designpattern.state.v1; 
 
/** 
 * <p> 
 * 状态模式 
 * </p> 
 */ 
public class StatePattern { 
 
    public static void main(String[] args) { 
        //创建环境   
        Context context = new Context(); 
        //处理请求 
        context.Handle(); 
        context.Handle(); 
        context.Handle(); 
        context.Handle(); 
    } 

 
//抽象状态类 
abstract class State { 
    public abstract void Handle(Context context); 

 
//具体状态A类 
class ConcreteStateA extends State { 
    public void Handle(Context context) { 
        System.out.println("当前状态是 A."); 
        context.setState(new ConcreteStateB()); 
    } 

 
//具体状态B类 
class ConcreteStateB extends State { 
    public void Handle(Context context) { 
        System.out.println("当前状态是 B."); 
        context.setState(new ConcreteStateA()); 
    } 

 
//环境类 
class Context { 
    private State state; 
 
    //定义环境类的初始状态 
    public Context() { 
        this.state = new ConcreteStateA(); 
    } 
 
    //设置新状态 
    public void setState(State state) { 
        this.state = state; 
    } 
 
    //读取状态 
    public State getState() { 
        return (state); 
    } 
 
    //对请求做处理 
    public void Handle() { 
        state.Handle(this); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.

输出结果如下:

  • 当前状态是 A.
  • 当前状态是 B.
  • 当前状态是 A.
  • 当前状态是 B.

解决的问题

对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。

 

模式组成

实例说明

实例概况

用“状态模式”设计一个多线程的状态转换程序。

 

分析:多线程存在 5 种状态,分别为新建状态、就绪状态、运行状态、阻塞状态和死亡状态,各个状态当遇到相关方法调用或事件触发时会转换到其他状态,其状态转换规律如下所示:

现在先定义一个抽象状态类(TheadState),然后为上图的每个状态设计一个具体状态类,它们是新建状态(New)、就绪状态(Runnable )、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Dead),每个状态中有触发它们转变状态的方法,环境类(ThreadContext)中先生成一个初始状态(New),并提供相关触发方法,下图所示是线程状态转换程序的结构图:

使用步骤

 

步骤1:定义抽象状态类:线程状态

abstract class ThreadState { 
    //状态名 
    protected String stateName; 

  • 1.
  • 2.
  • 3.
  • 4.

步骤2: 定义具体的状态类

//具体状态类:新建状态 
class New extends ThreadState { 
    public New() { 
        stateName = "新建状态"
        System.out.println("当前线程处于:新建状态."); 
    } 
 
    public void start(ThreadContext hj) { 
        System.out.print("调用start()方法-->"); 
        if (stateName.equals("新建状态")) { 
            hj.setState(new Runnable()); 
        } else { 
            System.out.println("当前线程不是新建状态,不能调用start()方法."); 
        } 
    } 

 
//具体状态类:就绪状态 
class Runnable extends ThreadState { 
    public Runnable() { 
        stateName = "就绪状态"
        System.out.println("当前线程处于:就绪状态."); 
    } 
 
    public void getCPU(ThreadContext hj) { 
        System.out.print("获得CPU时间-->"); 
        if (stateName.equals("就绪状态")) { 
            hj.setState(new Running()); 
        } else { 
            System.out.println("当前线程不是就绪状态,不能获取CPU."); 
        } 
    } 

 
//具体状态类:运行状态 
class Running extends ThreadState { 
    public Running() { 
        stateName = "运行状态"
        System.out.println("当前线程处于:运行状态."); 
    } 
 
    public void suspend(ThreadContext hj) { 
        System.out.print("调用suspend()方法-->"); 
        if (stateName.equals("运行状态")) { 
            hj.setState(new Blocked()); 
        } else { 
            System.out.println("当前线程不是运行状态,不能调用suspend()方法."); 
        } 
    } 
 
    public void stop(ThreadContext hj) { 
        System.out.print("调用stop()方法-->"); 
        if (stateName.equals("运行状态")) { 
            hj.setState(new Dead()); 
        } else { 
            System.out.println("当前线程不是运行状态,不能调用stop()方法."); 
        } 
    } 

 
//具体状态类:阻塞状态 
class Blocked extends ThreadState { 
    public Blocked() { 
        stateName = "阻塞状态"
        System.out.println("当前线程处于:阻塞状态."); 
    } 
 
    public void resume(ThreadContext hj) { 
        System.out.print("调用resume()方法-->"); 
        if (stateName.equals("阻塞状态")) { 
            hj.setState(new Runnable()); 
        } else { 
            System.out.println("当前线程不是阻塞状态,不能调用resume()方法."); 
        } 
    } 

 
//具体状态类:死亡状态 
class Dead extends ThreadState { 
    public Dead() { 
        stateName = "死亡状态"
        System.out.println("当前线程处于:死亡状态."); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.

步骤3:定义环境类

class ThreadContext { 
    private ThreadState state; 
 
    ThreadContext() { 
        state = new New(); 
    } 
 
    public void setState(ThreadState state) { 
        this.state = state; 
    } 
 
    public ThreadState getState() { 
        return state; 
    } 
 
    public void start() { 
        ((New) state).start(this); 
    } 
 
    public void getCPU() { 
        ((Runnable) state).getCPU(this); 
    } 
 
    public void suspend() { 
        ((Running) state).suspend(this); 
    } 
 
    public void stop() { 
        ((Running) state).stop(this); 
    } 
 
    public void resume() { 
        ((Blocked) state).resume(this); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.

输出结果

  • 当前线程处于:新建状态.
  • 调用start()方法-->当前线程处于:就绪状态.
  • 获得CPU时间-->当前线程处于:运行状态.
  • 调用suspend()方法-->当前线程处于:阻塞状态.
  • 调用resume()方法-->当前线程处于:就绪状态.
  • 获得CPU时间-->当前线程处于:运行状态.
  • 调用stop()方法-->当前线程处于:死亡状态.

优点

  1. 状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
  2. 减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
  3. 有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。

缺点

  1. 状态模式的使用必然会增加系统的类与对象的个数。
  2. 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。

应用场景

通常在以下情况下可以考虑使用状态模式。

  • 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
  • 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。

状态模式的扩展

 

在有些情况下,可能有多个环境对象需要共享一组状态,这时需要引入享元模式,将这些具体状态对象放在集合中供程序共享,其结构图如下:

分析:共享状态模式的不同之处是在环境类中增加了一个 HashMap 来保存相关状态,当需要某种状态时可以从中获取,其程序代码如下:

package com.niuh.designpattern.state.v3; 
 
import java.util.HashMap; 
 
/** 
 * <p> 
 * 共享状态模式 
 * </p> 
 */ 
public class FlyweightStatePattern { 
    public static void main(String[] args) { 
        //创建环境  
        ShareContext context = new ShareContext(); 
        //处理请求 
        context.Handle(); 
        context.Handle(); 
        context.Handle(); 
        context.Handle(); 
    } 

 
//抽象状态类 
abstract class ShareState { 
    public abstract void Handle(ShareContext context); 

 
//具体状态1类 
class ConcreteState1 extends ShareState { 
    public void Handle(ShareContext context) { 
        System.out.println("当前状态是: 状态1"); 
        context.setState(context.getState("2")); 
    } 

 
//具体状态2类 
class ConcreteState2 extends ShareState { 
    public void Handle(ShareContext context) { 
        System.out.println("当前状态是: 状态2"); 
        context.setState(context.getState("1")); 
    } 

 
//环境类 
class ShareContext { 
    private ShareState state; 
    private HashMap<String, ShareState> stateSet = new HashMap<String, ShareState>(); 
 
    public ShareContext() { 
        state = new ConcreteState1(); 
        stateSet.put("1", state); 
        state = new ConcreteState2(); 
        stateSet.put("2", state); 
        state = getState("1"); 
    } 
 
    //设置新状态 
    public void setState(ShareState state) { 
        this.state = state; 
    } 
 
    //读取状态 
    public ShareState getState(String key) { 
        ShareState s = (ShareState) stateSet.get(key); 
        return s; 
    } 
 
    //对请求做处理 
    public void Handle() { 
        state.Handle(this); 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.

输出结果如下

  • 当前状态是: 状态1
  • 当前状态是: 状态2
  • 当前状态是: 状态1
  • 当前状态是: 状态2

 

源码中的应用

#JDK中的状态模式: 
java.util.Iterator 
# 通过FacesServlet控制, 行为取决于当前JSF生命周期的阶段(状态 
javax.faces.lifecycle.LifeCycle#execute() 
  • 1.
  • 2.
  • 3.
  • 4.

PS:以上代码提交在 Github :

https://github.com/Niuh-Study/niuh-designpatterns.git

责任编辑:姜华 来源: 今日头条
相关推荐

2022-01-12 13:33:25

工厂模式设计

2020-11-03 13:05:18

命令模式

2020-10-23 09:40:26

设计模式

2021-06-09 08:53:34

设计模式策略模式工厂模式

2020-10-21 14:29:15

原型模式

2020-10-19 09:28:00

抽象工厂模式

2022-01-14 09:22:22

设计模式桥接

2013-11-26 15:48:53

Android设计模式SDK

2021-09-29 13:53:17

抽象工厂模式

2021-03-02 08:50:31

设计单例模式

2021-10-28 19:09:09

模式原型Java

2021-10-26 00:21:19

设计模式建造者

2020-11-09 08:20:33

解释器模式

2012-01-13 15:59:07

2020-10-20 13:33:00

建造者模式

2020-11-05 09:38:07

中介者模式

2020-10-28 11:56:47

桥接模式

2012-08-30 09:07:33

设计模式

2021-03-05 07:57:41

设计模式桥接

2020-10-26 08:45:39

观察者模式
点赞
收藏

51CTO技术栈公众号