正文

一、定义

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

要点:

  • 状态模式允许一个对象基于内部状态而拥有不同的行为。
  • 状态模式将状态封装成为独立的类,并将动作委托到代表当前状态的对象。
  • 通过将每个状态封装进一个类,我们把以后需要做的任何改变局部化了。

二、实现步骤

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 设计模式》:状态模式的更多相关文章

  1. <人人都懂设计模式>-状态模式

    同样是水,固态,气态,液态的变化,是由温度引起. 引此为思考状态模式. from abc import ABCMeta, abstractmethod # 引入ABCMeta和abstractmeth ...

  2. <人人都懂设计模式>-中介模式

    真正的用房屋中介来作例子, 好的书籍总是让人记忆深刻. class HouseInfo: def __init__(self, area, price, has_window, has_bathroo ...

  3. <人人都懂设计模式>-单例模式

    这个模式,我还是了解的. 书上用了三种不同的方法. class Singleton1: # 单例实现方式1 __instance = None __is_first_init = False def ...

  4. <人人都懂设计模式>-装饰模式

    书上,真的用一个人穿衣打拌来讲解装饰模式的呢. from abc import ABCMeta, abstractmethod class Person(metaclass=ABCMeta): def ...

  5. 14. 星际争霸之php设计模式--状态模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  6. 人人都懂区块链--pdf电子版学习资料下载

    人人都懂区块链 21天从区块链“小白”到资深玩家电子版pdf下载 链接:https://pan.baidu.com/s/1TWxYv4TLa2UtTgU-HqLECQ 提取码:6gy0 好的学习资料需 ...

  7. [Head First设计模式]生活中学设计模式——状态模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  8. 深入浅出设计模式——状态模式(State Pattern)

    模式动机 在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的 (stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的.当一个这样的 ...

  9. 24种设计模式--状态模式【State Pattern】

    现在城市发展很快,百万级人口的城市一堆一堆的,那其中有两个东西的发明在城市的发展中起到非常重要的作用:一个是汽车,一个呢是...,猜猜看,是什么?是电梯!汽车让城市可以横向扩展,电梯让城市可以纵向延伸 ...

  10. C++设计模式——状态模式

    前言 在实际开发中,我们经常会遇到这种情况:一个对象有多种状态,在每一个状态下,都会有不同的行为.那么在代码中我们经常是这样实现的. typedef enum tagState { state, st ...

随机推荐

  1. 第2章 Hive安装

    第2章 Hive安装 2.1 Hive安装地址 1.Hive官网地址 http://hive.apache.org/ 2.文档查看地址 https://cwiki.apache.org/conflue ...

  2. 手把手教Linux驱动3-之字符设备架构详解,有这篇就够了

    一.Linux设备分类 Linux系统为了管理方便,将设备分成三种基本类型: 字符设备 块设备 网络设备 字符设备: 字符(char)设备是个能够像字节流(类似文件)一样被访问的设备,由字符设备驱动程 ...

  3. Exploring Adversarial Attack in Spiking Neural Networks with Spike-Compatible Gradient

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! arXiv:2001.01587v1 [cs.NE] 1 Jan 2020 Abstract 脉冲神经网络(SNN)被广泛应用于神经形态设 ...

  4. 手写Promise简易版

    话不多说,直接上代码 通过ES5的模块化封装,向外暴露一个属性 (function(window){ const PENDING = 'pending'; const RESOLVED = 'fulf ...

  5. 赫然:怎样学习seo优化技术

    http://www.wocaoseo.com/thread-79-1-1.html 今天的题目是学习SEO起步阶段每个人都要问的.SEO怎么学?如何进阶SEO技能?都包括哪些知识?笔者也自己总结过一 ...

  6. html加C#上传文件

    最近在学上传文件部分内容,包括创建文件夹,设置文件夹属性,上传文件并保存. 前台代码: <html xmlns="http://www.w3.org/1999/xhtml"& ...

  7. BIO应用-RPC框架

    为什么要有RPC?  我们最开始开发的时候,一个应用一台机器,将所有功能都写在一起,比如说比较常见的电商场景. 随着我们业务的发展,我们需要提示性能了,我们会怎么做?将不同的业务功能放到线程里来实现异 ...

  8. SSM框架中添加写日志功能

    前提:要导入log4j的jar包 在web.xml中输入: <!--日志加载--> <context-param> <param-name>log4jConfigL ...

  9. 2.AVFormatContext和AVInputFormat

    参考https://blog.csdn.net/leixiaohua1020/article/details/14214705 AVFormatContext: 用来存储视音频封装格式(flv,mp4 ...

  10. 分布式事务框架.NetCore CAP总结

    来自CAP原作者yang-xiaodong的原理图: 本文撰写者:cmliu,部分内容引用自官方文档,部分内容待更新# .NetCore CAP # 1,简介 CAP 是一个遵循 .NET Stand ...