正文

一、定义

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

要点:

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

二、实现步骤

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. 【全解】Eclipse添加Spring项目插件

    1.Eclipse打开window-preference-InstallNewSoftware 2.先点Manage,取消掉The Eclipse Project Updates 3.选择Add . ...

  2. kvm-virtualization – 删除“孤儿”libvirt快照

    原文链接:https://codeday.me/bug/20181110/371346.html 创建快照: virsh snapshot-create-as --domain prod snap - ...

  3. 获取 python 包的路径

    root@ostack01:~# python Python 2.7. (default, Nov , ::) [GCC 5.4. ] on linux2 Type "help", ...

  4. 算法-排序(1)k路平衡归并与败者树

    const int MaxValue=; //根据实际情况选择最大值 void kwaymerge(Element *r,int k){ int i,q; r=new Element[k]; //在败 ...

  5. df卡死和fork:cannot allocate memory报错

    早上到了公司,发现docker资源池的某一台主机根文件系统写满. 检查后发现该主机/data目录未挂载文件系统,直接放在了根目录下.于是联系业务方将应用迁移,联系主机工程师为/data挂载80G的存储 ...

  6. qt exe文件添加图标

    Qt 怎样生成带图标的exe(转载) 一.问题描述 当我们在 Windows 下用 VS 生成 exe 程序时,如果窗口程序指定了图标,那么生成的 exe 程序便是指定的图标模样. 但是,当使用 Qt ...

  7. PyTorch入门-CIFAR10图像分类

    CIFAR10数据集下载 CIFAR10数据集包含10个类别,图像尺寸为 3×32×32 官方下载地址很慢,这里给一个百度云: https://pan.baidu.com/s/1oTvW8wNa-VO ...

  8. 源码浅入浅出 Java ConcurrentHashMap

    从源码的角度深入地分析了 ConcurrentHashMap 这个线程安全的 HashMap,希望能够给你一些帮助. 老读者就请肆无忌惮地点赞吧,微信搜索[沉默王二]关注这个在九朝古都洛阳苟且偷生的程 ...

  9. IDEA导入Eclipse的快捷键KeyMap

    说在前面的话 现在由于IDEA编辑器越来越火,因此很多程序员都从eclipse转入IDEA,转入后确实发现很强大的编辑器,但是一直为快捷键而忧愁,因为eclipse毕竟跟随了自己好多年了,突然更换编辑 ...

  10. 使用echarts 轻松搞定各种后台数据统计

    之前接到老大一个需求,需要将公私生态系统构建一个日志系统,统计公有云.私有云还有其他工具平台(如禅道,jenkins)的用户登录信息,并使用图标的形式动态显示,之前刚入门的时候接触过echarts 这 ...