状态模式

概述

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

适用场景

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

参与者

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));  
       }  
   }  
}

总结:

状态模式它主要用来解决对象在多种状态转换时,需要对外输出不同的结果的问题。状态和行为是一一对应的,状态之间可以互相转换。当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类。

全部评论

相关推荐

10-25 23:12
门头沟学院 Java
点赞 评论 收藏
分享
10-15 09:13
已编辑
天津大学 soc前端设计
点赞 评论 收藏
分享
评论
点赞
收藏
分享
正在热议
# 25届秋招总结 #
439972次浏览 4484人参与
# 春招别灰心,我们一人来一句鼓励 #
41352次浏览 523人参与
# 阿里云管培生offer #
119637次浏览 2219人参与
# 地方国企笔面经互助 #
7914次浏览 18人参与
# 虾皮求职进展汇总 #
113497次浏览 880人参与
# 实习,投递多份简历没人回复怎么办 #
2453683次浏览 34846人参与
# 北方华创开奖 #
107240次浏览 598人参与
# 实习必须要去大厂吗? #
55552次浏览 959人参与
# 同bg的你秋招战况如何? #
75178次浏览 548人参与
# 提前批简历挂麻了怎么办 #
149763次浏览 1976人参与
# 投递实习岗位前的准备 #
1195578次浏览 18546人参与
# 你投递的公司有几家约面了? #
33165次浏览 188人参与
# 双非本科求职如何逆袭 #
661770次浏览 7394人参与
# 机械人春招想让哪家公司来捞你? #
157585次浏览 2267人参与
# 如果公司给你放一天假,你会怎么度过? #
4714次浏览 53人参与
# 如果你有一天可以担任公司的CEO,你会做哪三件事? #
11214次浏览 253人参与
# 发工资后,你做的第一件事是什么 #
12359次浏览 61人参与
# 工作中,努力重要还是选择重要? #
35521次浏览 384人参与
# 参加完秋招的机械人,还参加春招吗? #
20068次浏览 240人参与
# 实习想申请秋招offer,能不能argue薪资 #
39205次浏览 314人参与
# 我的上岸简历长这样 #
451863次浏览 8087人参与
# 非技术岗是怎么找实习的 #
155831次浏览 2120人参与
牛客网
牛客企业服务