23种设计模式(22)java状态模式

 更新时间:2018年01月27日 10:42:14   作者:小吕-ICE  
这篇文章主要为大家详细介绍了23种设计模式之java状态模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

一、概述

当系统中某个对象存在多个状态,这些状态之间可以进行转换,而且对象在不同状态下行为不相同时可以使用状态模式。状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化。状态模式是一种对象行为型模式。

二、适用场景

用于解决系统中复杂对象的多种状态转换以及不同状态下行为的封装问题。简单说就是处理对象的多种状态及其相互转换。

三、UML类图


四、参与者

1)、AbstractState(抽象状态类):

        在抽象状态类中定义申明了不同状态下的行为抽象方法,而由子类(不同的状态子类)中实现不同的行为操作。

2)、ConcreteState(实现具体状态下行为的状态子类):

        抽象状态类的子类,每一个子类实现一个与环境类(Context)的一个状态相关的行为,每一个具体的状态类对应环境的一种具体状态,不同的具体状态其行为有所不同。

3)、Context(拥有状态对象的环境类):

        拥有状态属性,因环境的多样性,它可拥有不同的状态,且在不同状态下行为也不一样。在环境类中维护一个抽象的状态实例,这个实例定义当前环境的状态(setState()方法),而将具体的状态行为分离出来由不同的状态子类去完成。

五、用例学习

1、抽象状态类:State.java

/** 
* JAVA设计模式之 状态模式 
* 抽象状态类 
* @author lvzb.software@qq.com 
* 
*/ 
public abstract class State { 
  /** 
  * 状态行为抽象方法,由具体的状态子类去实现不同的行为逻辑 
  */ 
  public abstract void Behavior(); 
 
}

2、具体状态子类A:ConcreteStateA.java

/** 
* 具体的状态子类A 
* @author lvzb.software@qq.com 
*/ 
public class ConcreteStateA extends State { 
 
  @Override 
  public void Behavior() { 
    // 状态A 的业务行为, 及当为该状态下时,能干什么  
    // 如:手机在未欠费停机状态下, 能正常拨打电话 
    System.out.println("手机在未欠费停机状态下, 能正常拨打电话"); 
  } 
 
}

3、具体状态子类B:ConcreteStateB.java

/** 
* 具体的状态子类B 
* @author lvzb.software@qq.com 
* 
*/ 
public class ConcreteStateB extends State { 
 
  @Override 
  public void Behavior() { 
    // 状态B 的业务行为, 及当为该状态下时,能干什么 
    // 如:手机在欠费停机状态下, 不 能拨打电话 
    System.out.println("手机在欠费停机状态下, 不能拨打电话"); 
  } 
 
}

4、拥有状态对象的环境类:Context.java

/** 
* 环境/上下文类<br/> 
* 拥有状态对象,且可以完成状态间的转换 [状态的改变/切换 在环境类中实现] 
* @author lvzb.software@qq.com 
* 
*/ 
public class Context { 
  // 维护一个抽象状态对象的引用 
  private State state; 
   
  /* 
  * 模拟手机的话费属性<br/> 
  * 环境状态如下: 
  * 1>、当 bill >= 0.00$ : 状态正常  还能拨打电话 
  * 2>、当 bill < 0.00$ : 手机欠费  不能拨打电话 
  */ 
  private double bill; 
   
  /** 
  * 环境处理函数,调用状态实例行为 完成业务逻辑<br/> 
  * 根据不同的状态实例引用 在不同状态下处理不同的行为 
  */ 
  public void Handle(){ 
    checkState(); 
    state.Behavior(); 
  } 
   
   
  /** 
  * 检查环境状态:状态的改变/切换 在环境类中实现 
  */ 
  private void checkState(){ 
    if(bill >= 0.00){ 
      setState(new ConcreteStateA()); 
    } else { 
      setState(new ConcreteStateB()); 
    } 
  } 
   
   
  /** 
  * 设置环境状态<br/> 
  * 私有方法,目的是 让环境的状态由系统环境自身来控制/切换,外部使用者无需关心环境内部的状态 
  * @param state 
  */ 
  private void setState(State state){ 
    this.state = state; 
  } 
 
 
  public double getBill() { 
    return bill; 
  } 
 
  public void setBill(double bill) { 
    this.bill = bill; 
  } 
}

5、测试客户端调用类:Client.java

public class Client { 
 
  public static void main(String[] args) { 
    Context context = new Context(); 
    context.setBill(5.50); 
    System.out.println("当前话费余额:" + context.getBill() + "$"); 
    context.Handle(); 
     
    context.setBill(-1.50); 
    System.out.println("当前话费余额:" + context.getBill() + "$"); 
    context.Handle(); 
     
    context.setBill(50.00); 
    System.out.println("当前话费余额:" + context.getBill() + "$"); 
    context.Handle(); 
  } 
}

6、程序运行结果:

当前话费余额:5.5$ 
手机在未欠费停机状态下, 能正常拨打电话 
当前话费余额:-1.5$ 
手机在欠费停机状态下, 不能拨打电话 
当前话费余额:50.0$ 
手机在未欠费停机状态下, 能正常拨打电话

六、扩展 

状态模式中 关于状态的切换有两种不同的实现方式

方式一:状态的改变/切换  在环境类中实现。  如上面的用例代码Context类中的checkState()方法。

/** 
  * 检查环境状态:状态的改变/切换 在环境类中实现 
  */ 
  private void checkState(){ 
    if(bill >= 0.00){ 
      setState(new ConcreteStateA()); 
    } else { 
      setState(new ConcreteStateB()); 
    } 
  }

方式二:状态的改变/切换  在具体的状态子类中实现。

实现步骤如下:

1)、在环境类Context类中 初始化一个状态实例对象,并将环境Context对象作为子类状态的构造参数传递到具体的状态子类实例中。

如在Context.java类中

// 设置初始状态 
this.state = new ConcreteStateA(this);

2)、 在具体的子类状态类中根据构造进来的context对象,通过调用context对象的属性值进行业务逻辑判断 进行状态的检查和切换。

如在 具体的状态子类ConcreteStateA.java类中:

/** 
* 具体的状态子类A 
* @author lvzb.software@qq.com 
*/ 
public class ConcreteStateA extends State { 
  private Context ctx; 
   
  public ConcreteStateA(Context context){ 
    ctx = context; 
  } 
   
  @Override 
  public void Behavior() { 
    // 状态A 的业务行为, 及当为该状态下时,能干什么  
    // 如:手机在未欠费停机状态下, 能正常拨打电话 
    System.out.println("手机在未欠费停机状态下, 能正常拨打电话"); 
    checkState(); 
     
  } 
 
  /** 
  * 检查状态 是否需要进行状态的转换<br/> 
  * 状态的切换由具体状态子类中实现 
  */ 
  private void checkState(){ 
    if (ctx.getBill() < 0.00) { 
      ctx.setState(new ConcreteStateB(ctx)); 
    } 
  } 
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Feign 集成 Hystrix实现不同的调用接口不同的设置方式

    Feign 集成 Hystrix实现不同的调用接口不同的设置方式

    这篇文章主要介绍了Feign 集成 Hystrix实现不同的调用接口不同的设置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • SpringCloud Feign实现微服务之间相互请求问题

    SpringCloud Feign实现微服务之间相互请求问题

    Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地实现微服务之间的调用,这篇文章主要介绍了SpringCloud Feign实现微服务之间相互请求,需要的朋友可以参考下
    2022-06-06
  • Java数组去重复的18种方法示例

    Java数组去重复的18种方法示例

    这篇文章主要为大家介绍了Java数组去重复的18种写法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • SpringDataRedis入门和序列化方式解决内存占用问题小结

    SpringDataRedis入门和序列化方式解决内存占用问题小结

    spring-data-redis是spring-data模块的一部分,专门用来支持在spring管理项目对redis的操作,这篇文章主要介绍了SpringDataRedis入门和序列化方式解决内存占用问题,需要的朋友可以参考下
    2022-12-12
  • Java实现对象转CSV格式

    Java实现对象转CSV格式

    CSV是一种逗号分隔值格式的文件,一般用来存储数据的纯文本格式文件。Java对象转CSV,有现成的工具包,commons-lang3 的ReflectionToStringBuilder 就可以简单的解决的对象转CSV,快跟随小编一起学习一下吧
    2022-06-06
  • 三分钟读懂mybatis中resultMap和resultType区别

    三分钟读懂mybatis中resultMap和resultType区别

    这篇文章主要给大家介绍了mybatis中resultMap和resultType区别的相关资料,resultType和resultMap都是mybatis进行数据库连接操作处理返回结果的,需要的朋友可以参考下
    2023-07-07
  • Maven聚合开发实例详解

    Maven聚合开发实例详解

    这篇文章主要介绍了Maven聚合开发实例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • Java 中Flyway的使用详解

    Java 中Flyway的使用详解

    这篇文章主要介绍了Java 中Flyway的使用详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • Java根据模板实现excel导出标准化

    Java根据模板实现excel导出标准化

    这篇文章主要为大家详细介绍了Java如何根据模板实现excel导出标准化,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考下
    2024-03-03
  • Java8的常用时间api实用指南

    Java8的常用时间api实用指南

    这篇文章主要给大家介绍了关于Java8的常用时间api的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-11-11

最新评论