前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式----状态模式

设计模式----状态模式

作者头像
SuperHeroes
发布2018-05-30 17:02:53
5150
发布2018-05-30 17:02:53
举报
文章被收录于专栏:云霄雨霁云霄雨霁

状态模式:

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

状态模式的结构:

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

源代码:

环境角色类:

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

抽象状态角色:

代码语言:javascript
复制
public interface State {
    //状态对应的处理
    public void handle(String s);
}

具体状态角色:

代码语言:javascript
复制
//具体状态A
public class ConStateA implements State {
    public void handle(String s) {
        System.out.println("ConcreteStateA :" + s);
    }

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

}

测试方法:

代码语言:javascript
复制
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接口,每个状态类都要实现该接口:

代码语言:javascript
复制
public interface State {
	public void insertQuarter();
	public void ejectQuarter();
	public void turnCrank();
	public void dispense();
}

实现糖果机类:

代码语言:javascript
复制
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;
    }
 //更多方法
}

实现状态类:

代码语言:javascript
复制
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实例共享。
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.11.11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档