《Head First 设计模式》:状态模式
正文
一、定义
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
要点:
- 状态模式允许一个对象基于内部状态而拥有不同的行为。
- 状态模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象。
- 通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了。
二、实现步骤
1、创建状态接口
/**
* 状态接口
*/
public interface State {
/**
* 根据状态进行处理的方法
*/
public void handle();
}
2、在持有状态的类中,将请求委托给状态类
/**
* 持有状态的上下文类
*/
public class Context {
private State state;
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
/**
* 接收请求,并将请求委托给状态类
*/
public void request() {
state.handle();
}
}
3、创建具体的状态,并实现状态接口
(1)具体状态A
/**
* 具体状态A
*/
public class ConcreteStateA implements State {
Context context;
public ConcreteStateA() {
context = new Context();
}
@Override
public void handle() {
// 实现该状态下相应的行为
System.out.println("Context is in A state, and start to do something...");
context.setState(this);
}
}
(2)具体状态B
/**
* 具体状态B
*/
public class ConcreteStateB implements State {
Context context;
public ConcreteStateB() {
context = new Context();
}
@Override
public void handle() {
// 实现该状态下相应的行为
System.out.println("Context is in B state, and start to do something...");
context.setState(this);
}
}
4、通过改变状态,来改变上下文类的行为
public class Test {
public static void main(String[] args) {
// 上下文
Context context = new Context();
// 状态
State stateA = new ConcreteStateA();
State stateB = new ConcreteStateB();
// 通过状态改变行为
context.setState(stateA);
context.request();
context.setState(stateB);
context.request();
}
}
三、举个栗子
1、背景
万能糖果公司打算使用 Java 来实现糖果机的控制器。他们希望设计能够尽量有弹性而且好维护,因为将来可能要为糖果机增加更多的行为。
糖果机的工作流程如下:

2、实现
(1)创建状态接口,并定义相应的糖果机行为
/**
* 状态接口
*/
public interface State {
/**
* 投入25分钱
*/
public void insertQuarter();
/**
* 退回25分钱
*/
public void ejectQuarter();
/**
* 转动曲柄
*/
public void turnCrank();
/**
* 发放糖果
*/
public void dispense();
}
(2)创建糖果机
将传递给糖果机的请求,委托给状态类。
/**
* 糖果机
*/
public class GumballMachine {
State soldOutState;
State noQuarterState;
State hasQuarterState;
State soldState;
State state = soldOutState;
int gumballCount = 0;
public GumballMachine(int initGumballCount) {
soldOutState = new SoldOutState(this);
noQuarterState = new NoQuarterState(this);
hasQuarterState = new HasQuarterState(this);
soldState = new SoldState(this);
// 初始化糖果数量
this.gumballCount = initGumballCount;
// 初始化糖果机状态
if (initGumballCount > 0) {
state = noQuarterState;
} else {
state = soldOutState;
}
}
/**
* 投入25分钱
*/
public void insertQuarter() {
state.insertQuarter();
}
/**
* 退回25分钱
*/
public void ejectQuarter() {
state.ejectQuarter();
}
/**
* 转动曲柄
*/
public void turnCrank() {
state.turnCrank();
state.dispense();
}
/**
* 发放糖果
*/
public void releaseBall() {
System.out.println("A gumball comes rolling out the slot...");
if (gumballCount > 0) {
gumballCount = gumballCount -1;
}
}
public void setState(State state) {
this.state = state;
}
public int getGumballCount() {
return gumballCount;
}
public State getSoldOutState() {
return soldOutState;
}
public State getNoQuarterState() {
return noQuarterState;
}
public State getHasQuarterState() {
return hasQuarterState;
}
public State getSoldState() {
return soldState;
}
}
(3)创建具体的状态,并实现状态接口
/**
* 未投入25分钱状态
*/
public class NoQuarterState implements State {
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
// 投入25分钱,并转到已投入25分钱状态
System.out.println("You inserted a quarter");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
@Override
public void ejectQuarter() {
// 当前为未投入25分钱状态,不能退回25分钱
System.out.println("You haven't inserted a quarter");
}
@Override
public void turnCrank() {
// 当前为未投入25分钱状态,不能转动曲柄
System.out.println("You truned, but there's no quarter");
}
@Override
public void dispense() {
// 当前为未投入25分钱状态,不能发放糖果
System.out.println("You need to pay first");
}
}
/**
* 已投入25分钱状态
*/
public class HasQuarterState implements State {
GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
// 当前为已投入25分钱状态,不能再次投入
System.out.println("You can't insert another quarter");
}
@Override
public void ejectQuarter() {
// 退回25分钱,并将状态转到未投入25分钱状态
System.out.println("Quarter returned");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public void turnCrank() {
// 转动曲柄,并将状态转为售出状态
System.out.println("You turned...");
gumballMachine.setState(gumballMachine.getSoldState());
}
@Override
public void dispense() {
// 当前为已投入25分钱状态,还未转动曲柄,不能发放糖果
System.out.println("No gumball dispensed");
}
}
/**
* 售出状态
*/
public class SoldState implements State {
GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
// 当前为售出状态,不能再次投入25分钱
System.out.println("Please wait, we're already giving you a gumball");
}
@Override
public void ejectQuarter() {
// 当前为售出状态,不能退回25分钱
System.out.println("Sorry, you already truned the crank");
}
@Override
public void turnCrank() {
// 当前为售出状态,不能再次转动曲柄
System.out.println("Turning twice doesn't get you another gumball!");
}
@Override
public void dispense() {
// 发放糖果
gumballMachine.releaseBall();
if (gumballMachine.getGumballCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
System.out.println("Oops, out of gumballs!");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
/**
* 售罄状态
*/
public class SoldOutState implements State {
GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
// 当前为售罄状态,不能投入25分钱
System.out.println("You can't insert a quarter, the machine is sold out");
}
@Override
public void ejectQuarter() {
// 当前为售罄状态,不能要求退回25分钱
System.out.println("You can't eject, you haven't inserted a quarter yet");
}
@Override
public void turnCrank() {
// 当前为售罄状态,不能转动曲柄
System.out.println("You turned, but there are no gumballs");
}
@Override
public void dispense() {
// 当前为售罄状态,不能发放糖果
System.out.println("No gumball dispensed");
}
}
(4)操作糖果机
public class Test {
public static void main(String[] args) {
// 糖果机
GumballMachine gumballMachine = new GumballMachine(5);
// 正常操作
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
System.out.println("-----------------------");
// 异常操作
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
gumballMachine.turnCrank();
}
}
《Head First 设计模式》:状态模式的更多相关文章
- <人人都懂设计模式>-状态模式
同样是水,固态,气态,液态的变化,是由温度引起. 引此为思考状态模式. from abc import ABCMeta, abstractmethod # 引入ABCMeta和abstractmeth ...
- <人人都懂设计模式>-中介模式
真正的用房屋中介来作例子, 好的书籍总是让人记忆深刻. class HouseInfo: def __init__(self, area, price, has_window, has_bathroo ...
- <人人都懂设计模式>-单例模式
这个模式,我还是了解的. 书上用了三种不同的方法. class Singleton1: # 单例实现方式1 __instance = None __is_first_init = False def ...
- <人人都懂设计模式>-装饰模式
书上,真的用一个人穿衣打拌来讲解装饰模式的呢. from abc import ABCMeta, abstractmethod class Person(metaclass=ABCMeta): def ...
- 14. 星际争霸之php设计模式--状态模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- 人人都懂区块链--pdf电子版学习资料下载
人人都懂区块链 21天从区块链“小白”到资深玩家电子版pdf下载 链接:https://pan.baidu.com/s/1TWxYv4TLa2UtTgU-HqLECQ 提取码:6gy0 好的学习资料需 ...
- [Head First设计模式]生活中学设计模式——状态模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- 深入浅出设计模式——状态模式(State Pattern)
模式动机 在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的 (stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的.当一个这样的 ...
- 24种设计模式--状态模式【State Pattern】
现在城市发展很快,百万级人口的城市一堆一堆的,那其中有两个东西的发明在城市的发展中起到非常重要的作用:一个是汽车,一个呢是...,猜猜看,是什么?是电梯!汽车让城市可以横向扩展,电梯让城市可以纵向延伸 ...
- C++设计模式——状态模式
前言 在实际开发中,我们经常会遇到这种情况:一个对象有多种状态,在每一个状态下,都会有不同的行为.那么在代码中我们经常是这样实现的. typedef enum tagState { state, st ...
随机推荐
- Kettle基本使用
Kettle基本使用 Kettle的几个子程序的功能和启动方式 Spoon.bat 图形界面方式启动作业和转换设计器. Pan.bat 命令行方式执行转换. Kitchen.bat 命令行方式执行 ...
- SimpleXMLElement::addChild添加同级的空值xml节点
SimpleXMLElement::addChild添加同级的空值xml节点后,变成了其后面节点的父节点 解决方案:将节点以属性值的方式赋空值,$info->CONV_LEGAL_UNIT_NU ...
- springMVC入门(八)------拦截器
简介 springMVC拦截器针对处理器映射器进行拦截配置 如果在某个处理器映射器中配置拦截,经过该处理器映射器映射成功的Handler最终使用该拦截器 由于springMVC支持配置多个处理器映射器 ...
- springSecurity初识-练气初期
1.写在前面 Spring Security是一个框架,提供针对常见攻击的身份验证,授权和保护.通过对命令式和反应式应用程序的一流支持,它是保护基于Spring的应用程序的事实标准. Spring S ...
- Spring Cloud Config整合Spring Cloud Kubernetes,在k8s上管理配置
1 前言 欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章! Kubernetes有专门的ConfigMap和Secret来管理配置,但它也有一些局限性,所以还是希望通过Spring C ...
- 区块链入门到实战(21)之以太坊(Ethereum) – 分布式应用(DApp)
作用:用户交互 分布式应用(DApp)是运行在区块链之上的应用程序,支持区块链网络中用户之间的交互. DApp(decentralized application)的后端代码运行在区块链网络上,这个可 ...
- 《MySQL数据库》MySQL备份恢复
前言 MySQL数据库最重要的部分就是数据,所以保证数据不被损坏尤为重要,大家都知道911事件,当时非常多的数据丢失,导致经济混乱.接下来我们就来讲讲MySQL是如何保障数据完整,应对特殊情况,如何恢 ...
- java最简单的知识之创建一个简单的windows窗口,利用Frame类
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 QQ986945193 微博:http://weibo.com/mcxiaobing 首先给大家看一下 ...
- Substance Painter教程
https://huke88.com/route/substance-painter.html?sem=baidu&kw=106738
- 目标识别AI资料
朋友推荐的, 还有自己搜的. 入门可以看看. 网上资料应该不少, 一搜一大把, 简单记下地址. Review of Deep Learning Algorithms for Object Detect ...