状态模式 State (行为型模式)
1.概述
状态模式:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
例如:有一个账户,当余额大于等于0时,为正常状态,可以存款,取款;当-2000<=余额<0时,为透支状态,可以存款取款以及计算利息;当余额<-2000时,为限制状态,不能取款,可以存款,计算利息。根据账户余额的不同,状态会改变,每个状态的行为也会变化。
2.结构图
3.代码
1 /* 2 * 账户类 也是Context 环境类 3 */ 4 public class AccountContext { 5 6 private State state ;//持有一个对抽象状态对象的引用 7 private double account = 0D ;//账户初始金额 8 9 public AccountContext() { 10 this.state = new NormalState(this); 11 } 12 13 public void setState(State state) { 14 this.state = state; 15 } 16 public double getAccount() { 17 return account; 18 } 19 public void setAccount(double account) { 20 this.account = account; 21 } 22 23 public void deposit(double account){ 24 System.out.println("存款"+ account); 25 state.deposit(account); 26 System.out.println("现在余额为"+this.getAccount()); 27 System.out.println("现在状态为" + this.state.getClass().getName()); 28 System.out.println("----------------------"); 29 } 30 31 public void withdraw(double account){ 32 System.out.println("取款款"+ account); 33 state.withdraw(account); 34 System.out.println("现在余额为"+this.getAccount()); 35 System.out.println("现在状态为" + this.state.getClass().getName()); 36 System.out.println("----------------------"); 37 } 38 39 public void computeInterest(){ 40 41 state.computeInterest(); 42 } 43 44 45 }
1 public abstract class State { 2 3 protected AccountContext acc ; 4 public abstract void deposit(double account) ;//存钱 5 public abstract void withdraw(double account) ;//取钱 6 public abstract void computeInterest(); //计算利息 7 public abstract void stateCheck();//状态装换 8 9 }
1 /* 2 * 正常状态 3 */ 4 public class NormalState extends State { 5 6 public NormalState(AccountContext account) { 7 this.acc = account ; 8 } 9 10 public NormalState(State state) { 11 this.acc = state.acc; 12 } 13 14 @Override 15 public void deposit(double account) { 16 acc.setAccount(acc.getAccount() + account); 17 stateCheck(); 18 19 } 20 21 @Override 22 public void withdraw(double account) { 23 acc.setAccount(acc.getAccount() - account); 24 stateCheck(); 25 26 } 27 28 @Override 29 public void computeInterest() { 30 System.out.println("不用计算利息"); 31 32 } 33 34 @Override 35 public void stateCheck() { 36 if (acc.getAccount() > -2000 && acc.getAccount() <= 0) { 37 acc.setState(new OverdraftState(this)); 38 } 39 else if (acc.getAccount() <= -2000) { 40 acc.setState(new RestrictedState(this)); 41 } 42 43 44 } 45 46 }
1 /* 2 * 透支状态 3 */ 4 public class OverdraftState extends State { 5 6 public OverdraftState(AccountContext account) { 7 this.acc = account ; 8 } 9 10 public OverdraftState(State state) { 11 this.acc = state.acc; 12 } 13 14 @Override 15 public void deposit(double account) { 16 acc.setAccount(acc.getAccount() + account); 17 stateCheck(); 18 19 } 20 21 @Override 22 public void withdraw(double account) { 23 acc.setAccount(acc.getAccount() - account); 24 stateCheck(); 25 26 } 27 28 @Override 29 public void computeInterest() { 30 System.out.println("计算利息"); 31 32 } 33 34 //状态转换 35 public void stateCheck() { 36 if (acc.getAccount() > 0) { 37 acc.setState(new NormalState(this)); 38 } 39 else if (acc.getAccount() <= -2000) { 40 acc.setState(new RestrictedState(this)); 41 } 42 43 } 44 45 }
1 /* 2 * 限制状态 3 */ 4 public class RestrictedState extends State { 5 6 public RestrictedState(AccountContext account) { 7 this.acc = account ; 8 } 9 10 public RestrictedState(State state) { 11 this.acc = state.acc; 12 } 13 14 @Override 15 public void deposit(double account) { 16 acc.setAccount(acc.getAccount() + account); 17 stateCheck(); 18 19 } 20 21 @Override 22 public void withdraw(double account) { 23 System.out.println("无法取钱"); 24 25 } 26 27 @Override 28 public void computeInterest() { 29 System.out.println("计算利息"); 30 31 } 32 33 @Override 34 public void stateCheck() { 35 if(acc.getAccount() > 0) { 36 acc.setState(new NormalState(this)); 37 } 38 else if(acc.getAccount() > -2000) { 39 acc.setState(new OverdraftState(this)); 40 } 41 42 } 43 44 }
1 public class Test { 2 3 public static void main(String[] args) { 4 AccountContext context = new AccountContext(); 5 context.deposit(1000); 6 context.withdraw(2000); 7 context.withdraw(2000); 8 context.withdraw(2000); 9 context.computeInterest(); 10 11 12 } 13 14 }
状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化,对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理。
4.共享状态
在有些情况下,多个环境对象可能需要共享同一个状态,如果希望在系统中实现多个环境对象共享一个或多个状态对象,那么需要将这些状态对象定义为环境类的静态成员对象。
例如有多个开关对象,他们共同使用一个开状态,和一个关状态,当一个开关从开状态到关状态,其他开关都会变为关状态。
5.使用环境类实现状态转换
例如:玩射击游戏时,使用狙击枪,点击一下右键,切换到放大瞄准状态,再点一下右键,切换到更大倍率的放大,再点一下则回到正常状态。
这里可以将状态切换方法写在Context里,用if....else根据当前状态,切换到下一个状态,每点一下右键则调用这个方法。
缺点是如果需要增加新的方法,需要修改Context类。
6.优点
(1)将与特定状态相关的行为局部化,并将不同状态的行为分割开来。如果需要增加新的状态,只要再添加新的状态类就可以了。注入一个不同的状态对象即可使环境对象拥有不同的行为。
(2) 封装了状态的转换规则,在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。
(3)消除大量条件语句。
7.适用场景
(1)当一个对象的行为取决于它的状态,并且需要在运行时刻根据它的状态来改变它的行为。
参考:http://blog.csdn.net/lovelion/article/details/8522982