前言
文章内容主要参考了刘伟主编的《设计模式(第2版)》,同时也结合了自己的一些思考和理解,希望能帮到大家。
本篇讲解状态模式。
在一些情况当中,我们的一个环境可能会有多个状态进行切换,同时,如果单纯的通过当前的状态而在一些方法中大量的使用ifelse语句就会显得非常的冗余,耦合度高,所以便有了状态模式。
正文
一、定义
状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。
对于一个对象的多状态情况,以往的我们会用ifelse解决,但是在添加新的状态时,我们又要修改大量的代码。而我们其实注意到,1.一个对象是有多个不同的状态,它们需要不时的切换。2.当前状态决定当前允许有什么样的行为,而行为过后又有可能需要切换状态。
所以针对于此,状态模式的思考方式便是要把不同的状态单独分离出来,同时对于状态下的行为也一同封装在状态下。
其实状态模式有两个难点一个是理解行为怎么样在各状态下不同,第二个就是状态怎么切换的问题。
首先第一个,在我们过往认知中,行为是归属于对象的,所以对象有什么行为我们都是在这个对象中进行实现。而在状态模式中,对象的行为也依旧定义在自己身上,但是具体实现是调用具体状态类的方法,所以其实,行为是重心落在了各个状态中,我们是把状态和行为绑定在一起了,因为他们经常性的互相影响(不同状态决定不同行为,行为可能会切换不同状态)。对象类相当于一个空壳类。
第二个,每个对象中必然有个属性指向特定状态,在需要切换时,可以在行为调用后返回要切换的状态(不切换就return自身),又或者在需要切换时,通过双向关联修改对象的状态。具体看后面的实现可能会明白一些。
二、情景假设
在某银行系统定义的账户有三种状态:
(1) 如果账户(Account)中余额(balance)大于等于0,此时账户的状态为绿色(GreenState),即正常状态,表示既可以向该账户存款(deposit)也可以从该账户取款(withdraw);
(2) 如果账户中余额小于0,并且大于等于-1000,则账户的状态为黄色(YellowState),即欠费状态,此时既可以向该账户存款也可以从该账户取款;
(3) 如果账户中余额小于-1000,那么账户的状态为红色(RedState),即透支状态,此时用户只能向该账户存款,不能再从中取款。
现用状态模式来实现状态的转化问题,用户只需要执行简单的存款和取款操作,系统根据余额数量自动转换到相应的状态。
三、情景分析
关于上面情景的类图(具体分析在下面)
左边account类相当于定义了一个躯壳并且和一些属性。右边都是状态类,并且行为具体实现在各个状态类中发生。
最后为解决切换问题利用了双向关联。
环境类Account(注意看我注释的那一行)
public class Account {
private AccountState state;
private String owner;
public Account(String owner, double init){
this.owner = owner;
System.out.println(this.owner + "开户,初始账户为" + init);
System.out.println("----------------------");
this.state = new GreenState(init, this);//这里注意是把自身传进去,方便状态类使用其中的属性。
}
public void setState(AccountState state){
this.state = state;
}
public void deposit(double amount){
state.deposit(amount);
}
public String getOwner(){
return this.owner;
}
public void withdraw(double amount){
state.withdraw(amount);
}
}
抽象状态类AccountState
public abstract class AccountState {
protected Account acc;
protected double balance;
public abstract void stateCheck();
public void deposit(double amount){
System.out.println(acc.getOwner() + "存款" + amount);
this.balance += amount;
System.out.println("现在余额为" &