状态模式


声明:本文为博主原创文章,未经博主允许不得转载。

设计模式学习--状态模式(State Pattern)


概述
———————————————————————————————————————————————————
状态模式—允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。


OO原则
———————————————————————————————————————————————————
  • 封装变化
  • 多用组合,少用继承
  • 针对接口编程,不针对实现编程
  • 为交互对象之间的松耦合设计而努力
  • 类应该对扩展开放,对修改关闭
  • 依赖抽象,不要以来具体类
  • 只和朋友交谈
  • 别找我,我会找你
  • 类应该只有一个改变的理由


要点
———————————————————————————————————————————————————

  • 状态模式允许一个对象基于内部状态而拥有不用的行为。
  • 和程序状态机(PSM)不同,状态模式用类代表状态。
  • Context会将行为委托给当前状态对象。
  • 通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了。
  • 状态模式和策略模式有相同的类图,但是它们的意图不同。
  • 策略模式通常会用行为或算法来配置Context类。
  • 状态模式允许Context随着状态的改变而改变行为。
  • 状态转换可以由State类或Context类控制。
  • 使用状态模式通常会导致设计中类的数目大量增加。
  • 状态类可以被多个Context实例共享。

例子 糖果机
———————————————————————————————————————————————————

先来看一下状态模式的类图
状态模式_第1张图片


1. Context
定义客户感兴趣的接口。
维护一个ConcreteState子类的实例,这个实例定义当前状态。
GumballMachine.java

[java] view plain copy print ?
  1. package gumballstate;  
  2.   
  3. /** 
  4.  * 2013/7/12 
  5.  * @author wwj 
  6.  * 糖果机 
  7.  * 利用状态模式 
  8.  */  
  9. public class GumballMachine {  
  10.       
  11.     State soldOutState;         //售空状态  
  12.     State noQuarterState;       //没有投入25分钱  
  13.     State hasQuarterState;      //有25分钱了  
  14.     State soldState;            //出售状态  
  15.     State winnerState;          //10%的中奖率  
  16.       
  17.     State state = soldOutState;  
  18.     int count = 0;  
  19.       
  20.       
  21.     public GumballMachine(int numberGumballs) {  
  22.         soldOutState = new SoldOutState(this);  
  23.         noQuarterState = new NoQuarterState(this);  
  24.         hasQuarterState = new HasQuarterState(this);  
  25.         soldState = new SoldState(this);  
  26.         winnerState = new WinnerState(this);  
  27.         this.count = numberGumballs;  
  28.         if(numberGumballs > 0) {  
  29.             state = noQuarterState;  
  30.         }  
  31.     }  
  32.       
  33.       
  34.     public void insertQuarter() {  
  35.         state.insertQuarter();  
  36.     }  
  37.       
  38.       
  39.     public void ejectQuarter() {  
  40.         state.ejectQuarter();  
  41.     }  
  42.       
  43.     public void turnCrank() {  
  44.         state.turnCrank();  
  45.         state.dispense();  
  46.     }  
  47.       
  48.     void setState(State state) {  
  49.         this.state  = state;  
  50.     }  
  51.       
  52.       
  53.       
  54.     public State getState() {  
  55.         return state;  
  56.     }  
  57.   
  58.   
  59.     void releaseBall() {  
  60.         System.out.println("A gumball comes rolling out the slot...");  
  61.         if(count != 0) {  
  62.             count = count - 1;  
  63.         }  
  64.     }  
  65.   
  66.   
  67.     public State getSoldOutState() {  
  68.         return soldOutState;  
  69.     }  
  70.   
  71.   
  72.     public State getNoQuarterState() {  
  73.         return noQuarterState;  
  74.     }  
  75.   
  76.   
  77.     public State getHasQuarterState() {  
  78.         return hasQuarterState;  
  79.     }  
  80.   
  81.   
  82.     public State getSoldState() {  
  83.         return soldState;  
  84.     }  
  85.       
  86.       
  87.     public State getWinnerState() {  
  88.         return winnerState;  
  89.     }  
  90.   
  91.   
  92.     public int getCount() {  
  93.         return count;  
  94.     }  
  95.   
  96.   
  97.     public String toString() {  
  98.         StringBuffer result = new StringBuffer();  
  99.         result.append("\nMighty Gumball, Inc.");  
  100.         result.append("\nJava-enabled Standing Gumball Model #2004");  
  101.         result.append("\nInventory: " + count + " gumball");  
  102.         if (count != 1) {  
  103.             result.append("s");  
  104.         }  
  105.         result.append("\n");  
  106.         result.append("Machine is " + state + "\n");  
  107.         return result.toString();  
  108.     }  
  109.       
  110. }  




2.State
定义一个接口以封装与Context的一个特定状态相关的行为。
State.java
[java] view plain copy print ?
  1. package gumballstate;  
  2.   
  3. /** 
  4.  * 状态接口 
  5.  * @author wwj 
  6.  * 
  7.  */  
  8. public interface State {  
  9.     void insertQuarter();  
  10.     void ejectQuarter();  
  11.     void turnCrank();  
  12.     void dispense();  
  13. }  




3.ConcreteStateSubClasses
每一个子类实现与context的一个状态相关的行为
NoQuarterState.java
[java] view plain copy print ?
  1. package gumballstate;  
  2.   
  3.   
  4. /** 
  5.  * 2013/7/12 
  6.  * @author wwj 
  7.  * 实现状态接口状态类:没有25分钱 
  8.  */  
  9. public class NoQuarterState implements State {  
  10.     GumballMachine gumballMachine;  
  11.       
  12.     public NoQuarterState(GumballMachine gumballMachine2) {  
  13.         this.gumballMachine = gumballMachine2;  
  14.     }  
  15.   
  16.     @Override  
  17.     public void insertQuarter() {       //如果有人投入了25分钱,就将状态转换为HasQuarterState  
  18.         System.out.println("You inserted a quarter");  
  19.     }  
  20.   
  21.     @Override  
  22.     public void ejectQuarter() {        //如果没给钱,就不能要求退钱  
  23.         System.out.println("You haven't inserted a quarter");  
  24.     }  
  25.   
  26.     @Override  
  27.     public void turnCrank() {       //如果没给钱,就不能要求糖果  
  28.         System.out.println("You turned, but there's no quarter");  
  29.     }  
  30.   
  31.     @Override  
  32.     public void dispense() {        //如果没得到钱,我们就不能发放糖果  
  33.         System.out.println("You need to pay first");  
  34.     }  
  35.   
  36. }  

HasQuarterState.java
[java] view plain copy print ?
  1. package gumballstate;  
  2.   
  3. import java.util.Random;  
  4.   
  5. public class HasQuarterState implements State {  
  6.     Random randomWinner = new Random(System.currentTimeMillis());   //随机数产生器  
  7.     GumballMachine gumballMachine;  
  8.    
  9.     public HasQuarterState(GumballMachine gumballMachine) {  
  10.         this.gumballMachine = gumballMachine;  
  11.     }  
  12.     
  13.     public void insertQuarter() {  
  14.         System.out.println("You can't insert another quarter");  
  15.     }  
  16.    
  17.     public void ejectQuarter() {  
  18.         System.out.println("Quarter returned");  
  19.         gumballMachine.setState(gumballMachine.getNoQuarterState());  
  20.     }  
  21.    
  22.     public void turnCrank() {  
  23.         System.out.println("You turned...");  
  24.         int winner = randomWinner.nextInt(10);  //参数0~10的随机数  
  25.         if((winner == 0) && (gumballMachine.getCount() > 1)) {   //如果随机树为0,且足够的糖果的话,则可以得到两颗糖果  
  26.             gumballMachine.setState(gumballMachine.getWinnerState());  
  27.         } else {  
  28.             gumballMachine.setState(gumballMachine.getSoldState());  
  29.         }  
  30.     }  
  31.   
  32.     public void dispense() {  
  33.         System.out.println("No gumball dispensed");  
  34.     }  
  35.    
  36.     public String toString() {  
  37.         return "waiting for turn of crank";  
  38.     }  
  39. }  


SoldState.java
[java] view plain copy print ?
  1. package gumballstate;  
  2.   
  3. public class SoldState implements State {  
  4.    
  5.     GumballMachine gumballMachine;  
  6.    
  7.     public SoldState(GumballMachine gumballMachine) {  
  8.         this.gumballMachine = gumballMachine;  
  9.     }  
  10.          
  11.     public void insertQuarter() {  
  12.         System.out.println("Please wait, we're already giving you a gumball");  
  13.     }  
  14.    
  15.     public void ejectQuarter() {  
  16.         System.out.println("Sorry, you already turned the crank");  
  17.     }  
  18.    
  19.     public void turnCrank() {  
  20.         System.out.println("Turning twice doesn't get you another gumball!");  
  21.     }  
  22.    
  23.     public void dispense() {  
  24.         gumballMachine.releaseBall();  
  25.         if (gumballMachine.getCount() > 0) {  
  26.             gumballMachine.setState(gumballMachine.getNoQuarterState());  
  27.         } else {  
  28.             System.out.println("Oops, out of gumballs!");  
  29.             gumballMachine.setState(gumballMachine.getSoldOutState());  
  30.         }  
  31.     }  
  32.    
  33.     public String toString() {  
  34.         return "dispensing a gumball";  
  35.     }  
  36. }  

SoldOutState.java
[java] view plain copy print ?
  1. package gumballstate;  
  2.   
  3. public class SoldOutState implements State {  
  4.     GumballMachine gumballMachine;  
  5.    
  6.     public SoldOutState(GumballMachine gumballMachine) {  
  7.         this.gumballMachine = gumballMachine;  
  8.     }  
  9.    
  10.     public void insertQuarter() {  
  11.         System.out.println("You can't insert a quarter, the machine is sold out");  
  12.     }  
  13.    
  14.     public void ejectQuarter() {  
  15.         System.out.println("You can't eject, you haven't inserted a quarter yet");  
  16.     }  
  17.    
  18.     public void turnCrank() {  
  19.         System.out.println("You turned, but there are no gumballs");  
  20.     }  
  21.    
  22.     public void dispense() {  
  23.         System.out.println("No gumball dispensed");  
  24.     }  
  25.    
  26.     public String toString() {  
  27.         return "sold out";  
  28.     }  
  29. }  

WinnerState.java
[java] view plain copy print ?
  1. package gumballstate;  
  2.   
  3. public class WinnerState implements State {  
  4.     GumballMachine gumballMachine;  
  5.    
  6.     public WinnerState(GumballMachine gumballMachine) {  
  7.         this.gumballMachine = gumballMachine;  
  8.     }  
  9.    
  10.     public void insertQuarter() {  
  11.         System.out.println("Please wait, we're already giving you a Gumball");  
  12.     }  
  13.    
  14.     public void ejectQuarter() {  
  15.         System.out.println("Please wait, we're already giving you a Gumball");  
  16.     }  
  17.    
  18.     public void turnCrank() {  
  19.         System.out.println("Turning again doesn't get you another gumball!");  
  20.     }  
  21.    
  22.     public void dispense() {  
  23.         System.out.println("YOU'RE A WINNER! You get two gumballs for your quarter");  
  24.         gumballMachine.releaseBall();  
  25.         if (gumballMachine.getCount() == 0) {  
  26.             gumballMachine.setState(gumballMachine.getSoldOutState());  
  27.         } else {  
  28.             gumballMachine.releaseBall();  
  29.             if (gumballMachine.getCount() > 0) {  
  30.                 gumballMachine.setState(gumballMachine.getNoQuarterState());  
  31.             } else {  
  32.                 System.out.println("Oops, out of gumballs!");  
  33.                 gumballMachine.setState(gumballMachine.getSoldOutState());  
  34.             }  
  35.         }  
  36.     }  
  37.    
  38.     public String toString() {  
  39.         return "despensing two gumballs for your quarter, because YOU'RE A WINNER!";  
  40.     }  
  41. }  

测试
[java] view plain copy print ?
  1. package gumballstate;  
  2.   
  3. public class GumballMachineTestDrive {  
  4.   
  5.     public static void main(String[] args) {  
  6.         GumballMachine gumballMachine =   
  7.             new GumballMachine(10);  
  8.   
  9.         System.out.println(gumballMachine);  
  10.   
  11.         gumballMachine.insertQuarter();  
  12.         gumballMachine.turnCrank();  
  13.         gumballMachine.insertQuarter();  
  14.         gumballMachine.turnCrank();  
  15.   
  16.         System.out.println(gumballMachine);  
  17.   
  18.         gumballMachine.insertQuarter();  
  19.         gumballMachine.turnCrank();  
  20.         gumballMachine.insertQuarter();  
  21.         gumballMachine.turnCrank();  
  22.   
  23.         System.out.println(gumballMachine);  
  24.   
  25.         gumballMachine.insertQuarter();  
  26.         gumballMachine.turnCrank();  
  27.         gumballMachine.insertQuarter();  
  28.         gumballMachine.turnCrank();  
  29.   
  30.         System.out.println(gumballMachine);  
  31.   
  32.         gumballMachine.insertQuarter();  
  33.         gumballMachine.turnCrank();  
  34.         gumballMachine.insertQuarter();  
  35.         gumballMachine.turnCrank();  
  36.   
  37.         System.out.println(gumballMachine);  
  38.   
  39.         gumballMachine.insertQuarter();  
  40.         gumballMachine.turnCrank();  
  41.         gumballMachine.insertQuarter();  
  42.         gumballMachine.turnCrank();  
  43.   
  44.         System.out.println(gumballMachine);  
  45.     }  
  46. }  


Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 10 gumballs
Machine is waiting for quarter


You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...


Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 8 gumballs
Machine is waiting for quarter


You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...


Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 6 gumballs
Machine is waiting for quarter


You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...


Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 4 gumballs
Machine is waiting for quarter


You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...


Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 2 gumballs
Machine is waiting for quarter


You inserted a quarter
You turned...
A gumball comes rolling out the slot...
You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Oops, out of gumballs!


Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 0 gumballs
Machine is sold out

你可能感兴趣的:(状态模式)