博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【设计模式】学习笔记14:状态模式(State)
阅读量:4071 次
发布时间:2019-05-25

本文共 6487 字,大约阅读时间需要 21 分钟。

本文出自   

基本常识: 策略模式和状态模式是双胞胎,在出生时才分开

认识状态模式

假设有一个糖果机, 它的工作状态图如下:

要用代码实现糖果机的功能, 如果不用状态模式:

一种方法是创建一个类,它的作用就是一个状态机,对每一个动作,我们都创建了一个对应的方法,这些方法用条件语句来决定在每一个状态内什么方法是最恰当的.比如对"投入25分钱"这个动作,对应的方法如下:

// 我们根据糖果机的状态,定义4种状态,用整形常量来表示final static int SOLD_OUT= 0; // 糖果卖完了final static int NO_QUARTER = 1; // 没有投钱final static int HAS_QUARTER = 2;  // 已投钱了final static int SOLD = 3; // 正在出售糖果public void insertQurter() {        // 根据不同的状态,会有不同的动作反应    if (state == HAS_QUARTER) {        // do something         } else  if (state == SOLD_OUT) {        // do something         } else if (state == SOLD) {        // do something         } else if (state == NO_QUARTER) {        // do something         }}

这样做的缺点:
会产生大量的if...else语句, 代码将很不容易改变, 难以拓展.

没有遵守"开放-关闭"原则

不符合面向对象

状态转换隐藏在条件语句中,所以并不明显

没有把会改变的部分包装起来

未来加入的代码可能导致bug

是时候学习新的设计模式了

定义状态模式

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

因为这个模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象,我们知道行为会随着内部状态而改变。

Contex(上下文):是一个类,它可以拥有一些内部状态。

State接口:定义了一个所有具体状态的共同接口;任何状态都实现这个相同的接口,这样一来,状态之间可以互相替换

ConcreteState(具体状态): 处理来自Context的请求.每个ConcreteState都提供了它自己对于请求的实现.所以,当Context改变状态时行为也跟着改变

状态模式的类图和策略模式的基本一模一样, 但它们的"意图"不一样

状态模式允许Context随着状态的改变而改变行为.

策略模式通常会用行为或算法来配置Context类. 通常某个Context类只有一个最适当的策略.

使用状态模式通常那个会导致设计中的类数目大量增加. 因为"一个类,一个责任"原则

用状态模式实现糖果机

状态类图:
1. 实现State接口
public interface State {     // 封装四种动作	public void insertQuarter(); // 投币	public void ejectQuarter();  // 退币	public void turnCrank();     // 转动摇柄	public void dispense();      // 发糖果}
2. 实现具体的状态
// 没有投币的状态public class NoQuarterState implements State {    GumballMachine gumballMachine;     public NoQuarterState(GumballMachine gumballMachine) {        this.gumballMachine = gumballMachine;    } 	public void insertQuarter() {		System.out.println("You inserted a quarter");		gumballMachine.setState(gumballMachine.getHasQuarterState());	} 	public void ejectQuarter() {		System.out.println("You haven't inserted a quarter");	} 	public void turnCrank() {		System.out.println("You turned, but there's no quarter");	 } 	public void dispense() {		System.out.println("You need to pay first");	}  	public String toString() {		return "waiting for quarter";	}}
// 已经投币的状态public class HasQuarterState implements State {	GumballMachine gumballMachine; 	public HasQuarterState(GumballMachine gumballMachine) {		this.gumballMachine = gumballMachine;	}  	public void insertQuarter() {		System.out.println("You can't insert another quarter");	} 	public void ejectQuarter() {		System.out.println("Quarter returned");		gumballMachine.setState(gumballMachine.getNoQuarterState());	} 	public void turnCrank() {		System.out.println("You turned...");		gumballMachine.setState(gumballMachine.getSoldState());	}    public void dispense() {        System.out.println("No gumball dispensed");    } 	public String toString() {		return "waiting for turn of crank";	}}
// 正在售出的状态public class SoldState implements State {     GumballMachine gumballMachine;     public SoldState(GumballMachine gumballMachine) {        this.gumballMachine = gumballMachine;    }       	public void insertQuarter() {		System.out.println("Please wait, we're already giving you a gumball");	} 	public void ejectQuarter() {		System.out.println("Sorry, you already turned the crank");	} 	public void turnCrank() {		System.out.println("Turning twice doesn't get you another gumball!");	} 	public void dispense() {		gumballMachine.releaseBall();		if (gumballMachine.getCount() > 0) {			gumballMachine.setState(gumballMachine.getNoQuarterState());		} else {			System.out.println("Oops, out of gumballs!");			gumballMachine.setState(gumballMachine.getSoldOutState());		}	} 	public String toString() {		return "dispensing a gumball";	}}
// 售完的状态public class SoldOutState implements State {    GumballMachine gumballMachine;     public SoldOutState(GumballMachine gumballMachine) {        this.gumballMachine = gumballMachine;    } 	public void insertQuarter() {		System.out.println("You can't insert a quarter, the machine is sold out");	} 	public void ejectQuarter() {		System.out.println("You can't eject, you haven't inserted a quarter yet");	} 	public void turnCrank() {		System.out.println("You turned, but there are no gumballs");	} 	public void dispense() {		System.out.println("No gumball dispensed");	} 	public String toString() {		return "sold out";	}}
3. 实现Context
public class GumballMachine { 	State soldOutState;	State noQuarterState;	State hasQuarterState;	State soldState; 	State state = soldOutState;	int count = 0; 	public GumballMachine(int numberGumballs) {		soldOutState = new SoldOutState(this);		noQuarterState = new NoQuarterState(this);		hasQuarterState = new HasQuarterState(this);		soldState = new SoldState(this);		this.count = numberGumballs; 		if (numberGumballs > 0) {			state = noQuarterState;		} 	} 	public void insertQuarter() {		state.insertQuarter();	} 	public void ejectQuarter() {		state.ejectQuarter();	} 	public void turnCrank() {		state.turnCrank();		state.dispense();	}	void setState(State state) {		this.state = state;	} 	void releaseBall() {		System.out.println("A gumball comes rolling out the slot...");		if (count != 0) {			count = count - 1;		}	} 	int getCount() {		return count;	} 	void refill(int count) {		this.count = count;		state = noQuarterState;	}    public State getState() {        return state;    }    public State getSoldOutState() {        return soldOutState;    }    public State getNoQuarterState() {        return noQuarterState;    }    public State getHasQuarterState() {        return hasQuarterState;    }    public State getSoldState() {        return soldState;    } 	public String toString() {		StringBuffer result = new StringBuffer();		result.append("\nMighty Gumball, Inc.");		result.append("\nJava-enabled Standing Gumball Model #2004");		result.append("\nInventory: " + count + " gumball");		if (count != 1) {			result.append("s");		}		result.append("\n");		result.append("Machine is " + state + "\n");		return result.toString();	}}
4. 测试类
public class GumballMachineTestDrive {	public static void main(String[] args) {		GumballMachine gumballMachine = new GumballMachine(5);		System.out.println(gumballMachine);		gumballMachine.insertQuarter();		gumballMachine.turnCrank();		System.out.println(gumballMachine);		gumballMachine.insertQuarter();		gumballMachine.turnCrank();		gumballMachine.insertQuarter();		gumballMachine.turnCrank();		System.out.println(gumballMachine);	}}
这样做的优点:

1. 将每个状态的行为局部化到自己的类中

2. 将容易产生问题的if语句删除,以方便日后的维护

3. 让每个状态"对修改关闭",让糖果机"对拓展开放",因为可以加入新的状态类

4. 创建一个新的代码基和类结构,这更能映射糖果的图,而且容易阅读和理解

你可能感兴趣的文章
linux对于没有写权限的文件如何保存退出vim
查看>>
Windows下安装ElasticSearch6.3.1以及ElasticSearch6.3.1的Head插件
查看>>
IntelliJ IDEA 下的svn配置及使用的非常详细的图文总结
查看>>
【IntelliJ IDEA】idea导入项目只显示项目中的文件,不显示项目结构
查看>>
ssh 如何方便的切换到其他节点??
查看>>
JSP中文乱码总结
查看>>
Java-IO-File类
查看>>
Java-IO-java的IO流
查看>>
Java-IO-输入/输出流体系
查看>>
Java实现DES加密解密
查看>>
HTML基础
查看>>
Java IO
查看>>
Java NIO
查看>>
Java大数据:Hbase分布式存储入门
查看>>
大数据学习:Spark RDD操作入门
查看>>
大数据框架:Spark 生态实时流计算
查看>>
大数据入门:Hive和Hbase区别对比
查看>>
大数据入门:ZooKeeper工作原理
查看>>
大数据入门:Zookeeper结构体系
查看>>
大数据入门:Spark RDD基础概念
查看>>