博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式----状态模式
阅读量:6804 次
发布时间:2019-06-26

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

hot3.png

状态模式:

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

状态模式的结构:

  • 环境(Context)角色,也称上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
  • 抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
  • 具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

源代码:

环境角色类:

public class Context {    //持有一个State类型的对象实例    private State state;    public void setState(State state) { this.state = state; }        //用户感兴趣的接口方法    public void request(String s) {        //转调state来处理        state.handle(s);    }}

抽象状态角色:

public interface State {    //状态对应的处理    public void handle(String s);}

具体状态角色:

//具体状态Apublic class ConStateA implements State {    public void handle(String s) {        System.out.println("ConcreteStateA :" + s);    }}//具体状态Bpublic class ConStateB implements State {    public void handle(String s) {        System.out.println("ConcreteStateB :" + s);    }}

测试方法:

public class Client {    public static void main(String[] args){        //创建状态        State state = new ConcreteStateB();        //创建环境        Context context = new Context();        //将状态设置到环境中        context.setState(state);        //请求        context.request("test");    }}

示例:糖果机

糖果机工作如上图所示,这个例子中,糖果机是环境,每一个圆圈都是一个具体状态,而每一个箭头都是状态之间的转换。

我们使用状态模式来重写代码:

  1. 首先定义一个state接口。这个接口内糖果机每个动作都有一个对应的方法。
  2. 然后为机器中的每个状态实现状态类。这些类将负责在对应的状态下进行机器的行为。
  3. 最后将动作委托到状态类。

实现state接口,每个状态类都要实现该接口:

public interface State {	public void insertQuarter();	public void ejectQuarter();	public void turnCrank();	public void dispense();}

实现糖果机类:

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() {//注意这里和其他两个的区别。dispense是一个内部动作,用户不能直接要求发放糖果。用户转动手柄turnCrack()方法调用dispense()		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;    } //更多方法}

实现状态类:

import java.util.Random;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 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 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";	}}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";	}}

要点:

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

转载于:https://my.oschina.net/HuoQibin/blog/1571727

你可能感兴趣的文章
信息化一周回顾:金融业大数据十大趋势
查看>>
Http、TCP/IP协议与Socket之间的区别
查看>>
文思海辉:智慧数据避免企业成为大数据时代落伍者
查看>>
迅雷发布“星域CDN” 做条颠覆市场的鲶鱼
查看>>
英国《数字经济法案》
查看>>
Asp.net与Flex交互测试记录
查看>>
运维前线:一线运维专家的运维方法、技巧与实践1.8 运维自动化依赖的团队模型...
查看>>
《树莓派渗透测试实战》——第1章 树莓派和Kali Linux基础知识
查看>>
《圣殿祭司的ASP.NET4.0专家技术手册》----1-7 HTML5与CSS3的支持
查看>>
数据结构之链表
查看>>
八年了必须放手了,我不是你妈妈
查看>>
Eric S. Raymond 五部曲
查看>>
《Ansible权威指南 》一2.7 本章小结
查看>>
《iOS编程指南》——2.4节安装iOS SDK
查看>>
Comparing Mongo DB and Couch DB
查看>>
《配置管理最佳实践》——1.6 工具的选择
查看>>
前端工程师如何快速的开发一个微信JSSDK应用
查看>>
Apache Spark源码走读(九)如何进行代码跟读&使用Intellij idea调试Spark源码
查看>>
Android应用安全开发之浅谈网页打开APP
查看>>
后退时保存表单状态
查看>>