设计模式——状态模式
定义:允许一个对象在其内部状态发生改变时改变它的行为,对象看起来似乎修改了它的类。
**成员:**Context(环境)、State(抽象状态类)、ConcreteState(具体状态类)
**理解:**这种模式在生活中的应用也很广泛,比如当你和朋友打牌,一开始手上有100块,输了一把,一下输了200块,此时你就从有资产的正常状态变成了负债状态。可以发现,你作为一个环境对象,当你执行了输钱这个操作后,你的资产从正的变为负的,从而导致你的状态从正常状态变为了负债状态。而我们知道,当你的状态为正常状态时,你还可以参与打牌这个游戏,或者一些其它需要钱的活动,而当你的状态变为负债状态后,很多需要钱的活动将不能参与,就像是突然之间,这个你这个环境对象中少了很多的方法,看起来你的类在执行输钱这个操作后似乎被修改了。
从上面的叙述中,可以看出,你作为一个环境变量,应该有资产数量和资产状态这个两个成员变量,而资产状态这个成员变量决定了环境变量所能执行的操作,比如资产状态为负债状态,你作为一个环境变量就无法继续参与打牌这个操作。此外,状态转化的过程应该是自发的,即在输钱的时候,一旦总资产小于0,环境变量的状态就自发的转变为负债状态。而状态的转化首先必定需要检查资产数量。而这个对资产数量进行检查的操作应该发生在什么时机呢?没错,这个检查资产数量的操作应该存在于每一个访问了资产数量的操作之后,即:在每一次涉及对资产数量进行访问的操作之后,都要进行一次资产数量的检查。一旦发现资产为负数,就立即将状态转化为负债状态。
前面又说过,资产状态这个成员变量决定了环境变量所能执行的操作,因此,环境变量所能执行的所有操作应该由资产状态这个成员变量来调用。
类图如下:
代码如下:
//环境类:用户
public class User{
int money;//资产数量成员
State state;//状态成员
public User(int money){
this.money = money;
state = new NormalState(this);
}
public void setState(State state){
this.state = state;
}
public void gamble(){
state.gamble();
}
public void makeMoney() {
state.makeMoney();
}
}
//抽象状态类
public abstract class State{
User user;
public abstract class stateCheck();//对资产数量进行检查的操作
}
//具体状态类:资产正常
public class NormalState extends State{
public NormalState(User user){
this.user = user;
}
public NormalState(State state){
this.user = state.user;
}
public void gamble(){
user.money -= 200;//只要一执行打牌这个操作,就输200
stateCheck();
}
public void makeMoney(){
user.money += 200;//赚钱操作,一次赚200
stateCheck();
}
public void stateCheck(){
if(user.money < 0)
user.setState(new IndebtedState(this));
else{}
}
}
//具体状态类:负债状态
public class IndebtedState{
public IndebtedState(User user){
this.money = user.money;
this.user = user;
}
public IndebtedState(State state){
this.money = state.money;
this.user = state.user;
}
public void gamble(){
System.out.println("你当前为负债状态,不能再打牌了.");
}
public void makeMoney(){
user.money += 200;//赚钱操作,一次赚200
stateCheck();
}
public void stateCheck(){
if(user.money > 0)
user.setState(new NormalState(this));
else{}
}
}
交互关系如下:
public Client{
public static void main(String args[]){
User user = new User(100);
user.gamble();//执行此操作后将变为负债状态
user.gamble();//此时将会打印"你当前为负债状态,不能再打牌了."
user.makeMoney();//执行此操作后再次变为正常状态
}
}
说明:状态模式封装了状态的转换规则。将转换逻辑与状态对象合成一体,而不是一个巨大的条件语句块。但是,对添加新的状态不太友好,因为添加新的状态就要修改其他状态类的转换逻辑,不符合开闭原则。
该模式的适用场景:存在对象拥有多种状态,这些状态可以相互转换,而且对象状态不同时,其行为也有所差异。对于这种类型的对象,可以通过此模式对其进行设计,使得用户可以灵活地切换状态且用户在使用过程中无需关心对象状态及其切换细节。