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

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

 

本文出自   

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

认识状态模式

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

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

一种方法是创建一个类,它的作用就是一个状态机,对每一个动作,我们都创建了一个对应的方法,这些方法用条件语句来决定在每一个状态内什么方法是最恰当的.比如对"投入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";	}}
.....
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. 创建一个新的代码基和类结构,这更能映射糖果的图,而且容易阅读和理解

 

转载于:https://www.cnblogs.com/bbsno1/p/3275638.html

你可能感兴趣的文章
ajax传值后在新页面js调用
查看>>
Spring 中使用 Mybatis generator 自动生成代码
查看>>
IP通信基础 4月8日
查看>>
【模板】树状数组1
查看>>
js 编码问题
查看>>
boost::function()的用法
查看>>
php 经典算法
查看>>
一致性哈希算法的稳定性检测和它存在的问题及解决策略
查看>>
Aspx小记
查看>>
升级到了IE11,在IE9以上无法加载css
查看>>
VIM下的跳转练习
查看>>
WPF TextBox PreviewTextInput handle IME (chinese)
查看>>
LR报:Error 27796 Failed to connect to server
查看>>
bzoj 2109: [Noi2010]Plane 航空管制
查看>>
哈姆雷特中大臣给即将远行儿子的忠告------流传百年的经典
查看>>
[*leetcode 22] Generate Parentheses
查看>>
[levelDB] Version Manager
查看>>
mumu模拟机安装证书
查看>>
[python]Pytest+selenium+git+jenkins持续集成
查看>>
瀑布流知识的延伸
查看>>