状态设计模式示例

本文是我们名为“ Java设计模式 ”的学院课程的一部分。

在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看

1.简介

为了说明“状态设计模式”的使用,让我们帮助一家正在寻求制造烹饪机器人的公司。 该公司想要一个简单的机器人,它可以简单地走路和煮饭。 用户可以通过遥控器使用一组命令来操作机器人。 当前,机器人可以做三件事,它可以走路,做饭或关闭。

该公司已设置协议来定义机器人的功能。 如果机器人处于“开启”状态,则可以命令它行走。 如果要求烹饪,则状态将更改为“烹饪”,或者设置为“关闭”,则将其关闭。

同样,处于“烹饪”状态时,它可以走路或做饭,但不能关闭。 最后,当处于“关闭”状态时,当用户命令它走路但不能在关闭状态下烹饪时,它将自动上走。

这可能看起来像是一个简单的实现:机器人类具有一组方法,如走动,烹饪,关闭以及状态(如打开,烹饪和关闭)。 我们可以使用if-else分支或使用switch来实现公司设置的协议。 但是过多的if-else或switch语句将造成维护的噩梦,因为将来的复杂性可能会增加。

您可能认为我们可以使用if-else语句来实现此目的,但是随着更改的来临,代码将变得更加复杂。 需求清楚地表明,对象的行为确实基于该对象的状态。 我们可以使用状态设计模式,该模式将对象的状态封装到另一个单独的类中,并使上下文类独立于任何状态更改。

首先让我们了解状态设计模式,然后将其实现以解决上述问题。

2.什么是状态设计模式

状态设计模式允许对象在其内部状态更改时更改其行为。 该对象似乎将更改其类。

可以将对象的状态定义为在任何给定时间点的确切条件,具体取决于其属性或属性的值。 由类实现的方法集构成其实例的行为。 只要它的属性值发生变化,我们就说对象的状态已发生变化。

状态模式可用于为类设计有效的结构,该类的典型实例可以存在于许多不同的状态中,并根据其所处的状态而表现出不同的行为。换句话说,对于此类对象,类,其某些或全部行为完全受其当前状态影响。 在状态设计模式术语中,此类称为Context类。 当内部状态发生变化时, Context对象可以更改其行为,也称为有状态对象。

状态模式建议将特定于状态的行为从Context类中移到一组单独的类中,这些类称为State类。 Context对象可以存在的许多不同状态中的每一个都可以映射到单独的State类中。 State类的实现包含特定于给定状态的上下文行为,而不是上下文本身的整体行为。 从某种意义上说,上下文是状态对象集的客户端,它利用不同的状态对象为无缝使用上下文的应用程序对象提供必要的特定于状态的行为。

通过将特定于状态的行为封装在单独的类中,上下文实现变得更易于阅读:无需太多条件语句(例如if-else或switch-case构造)。 首次创建Context对象时,它将使用其初始State对象进行初始化。 该State对象成为上下文的当前State对象。 通过用新的State对象替换当前的State对象,上下文将转换为新的状态。

使用上下文的客户端应用程序不负责为上下文指定当前的State对象,而是代表特定状态的每个State类均应提供将上下文转换为其他状态的必要实现。 当应用程序对象调用Context方法(行为)时,它将方法调用转发到其当前的State对象。

图1-类图

图1 –类图

语境

  • 定义客户感兴趣的界面。
  • 维护定义当前状态的ConcreteState子类的实例。

  • 定义用于封装与Context的特定状态关联的行为的接口。

ConcreteState子类

  • 每个子类都实现与Context状态关联的行为。

3.实施状态设计模式

以下是RoboticState接口,其中包含机器人的行为。

package com.javacodegeeks.patterns.statepattern;

public interface RoboticState {

	public void walk();
	public void cook();
	public void off();

}

Robot类是实现RoboticState接口的具体类。 该类包含机器人可能处于的所有可能状态的集合。

package com.javacodegeeks.patterns.statepattern;

public class Robot implements RoboticState{

	private RoboticState roboticOn;
	private RoboticState roboticCook;
	private RoboticState roboticOff;

	private RoboticState state;

	public Robot(){
		this.roboticOn = new RoboticOn(this);
		this.roboticCook = new RoboticCook(this);
		this.roboticOff = new RoboticOff(this);

		this.state = roboticOn;
	}

	public void setRoboticState(RoboticState state){
		this.state = state;
	}

	@Override
	public void walk() {
		state.walk();
	}

	@Override
	public void cook() {
		state.cook();

	}

	@Override
	public void off() {
		state.off();
	}

	public RoboticState getRoboticOn() {
		return roboticOn;
	}

	public void setRoboticOn(RoboticState roboticOn) {
		this.roboticOn = roboticOn;
	}

	public RoboticState getRoboticCook() {
		return roboticCook;
	}

	public void setRoboticCook(RoboticState roboticCook) {
		this.roboticCook = roboticCook;
	}

	public RoboticState getRoboticOff() {
		return roboticOff;
	}

	public void setRoboticOff(RoboticState roboticOff) {
		this.roboticOff = roboticOff;
	}

	public RoboticState getState() {
		return state;
	}

	public void setState(RoboticState state) {
		this.state = state;
	}

}

该类初始化所有状态并将当前状态设置为on。

现在,我们将看到机器人的所有具体状态。 机器人将随时处于任何一种状态。

package com.javacodegeeks.patterns.statepattern;

public class RoboticOn implements RoboticState{

	private final Robot robot;

	public RoboticOn(Robot robot){
		this.robot = robot;
	}

	@Override
	public void walk() {
		System.out.println("Walking...");
	}

	@Override
	public void cook() {
		System.out.println("Cooking...");
		robot.setRoboticState(robot.getRoboticCook());
	}

	@Override
	public void off() {
		robot.setState(robot.getRoboticOff());
		System.out.println("Robot is switched off");

	}

}
package com.javacodegeeks.patterns.statepattern;

public class RoboticCook implements RoboticState{

	private final Robot robot;

	public RoboticCook(Robot robot){
		this.robot = robot;
	}

	@Override
	public void walk() {
		System.out.println("Walking...");
		robot.setRoboticState(robot.getRoboticOn());
	}

	@Override
	public void cook() {
		System.out.println("Cooking...");
	}

	@Override
	public void off() {
		System.out.println("Cannot switched off while cooking...");
	}
}
package com.javacodegeeks.patterns.statepattern;

public class RoboticOff implements RoboticState{

	private final Robot robot;

	public RoboticOff(Robot robot){
		this.robot = robot;
	}

	@Override
	public void walk() {
		System.out.println("Walking...");
		robot.setRoboticState(robot.getRoboticOn());
	}

	@Override
	public void cook() {
		System.out.println("Cannot cook at Off state.");
	}

	@Override
	public void off() {
		System.out.println("Already switched off...");
	}
}

现在,让我们测试代码。

package com.javacodegeeks.patterns.statepattern;

public class TestStatePattern {

	public static void main(String[] args) {
		Robot robot = new Robot();
		robot.walk();
		robot.cook();
		robot.walk();
		robot.off();

		robot.walk();
		robot.off();
		robot.cook();

	}

}

上面的代码将导致以下输出:

Walking...
Cooking...
Walking...
Robot is switched off
Walking...
Robot is switched off
Cannot cook at Off state.

在上面的示例中,我们已经看到通过将对象的状态封装到不同的类中可以使代码易于管理和灵活。

状态的任何更改只会影响该特定的类,我们可以在不更改现有代码的情况下包括一个新状态。 例如,我们包含一个备用状态。 散步或做饭后,机器人进入待机模式以节省电量,然后我们再次步行,做饭或从待机模式下关闭。

为了实现所有这些,我们需要引入一个新的状态类,并将该状态包括在Robot类中。 以下是更改。

package com.javacodegeeks.patterns.statepattern;

public class Robot implements RoboticState{

	private RoboticState roboticOn;
	private RoboticState roboticCook;
	private RoboticState roboticOff;
	private RoboticState roboticStandby;

	private RoboticState state;

	public Robot(){
		this.roboticOn = new RoboticOn(this);
		this.roboticCook = new RoboticCook(this);
		this.roboticOff = new RoboticOff(this);
		this.roboticStandby = new RoboticStandby(this);

		this.state = roboticOn;
	}

	public void setRoboticState(RoboticState state){
		this.state = state;
	}

	@Override
	public void walk() {
		state.walk();
		setState(getRoboticStandby());
	}

	@Override
	public void cook() {
		state.cook();
		setState(getRoboticStandby());
	}

	@Override
	public void off() {
		state.off();
	}

	public RoboticState getRoboticOn() {
		return roboticOn;
	}

	public void setRoboticOn(RoboticState roboticOn) {
		this.roboticOn = roboticOn;
	}

	public RoboticState getRoboticCook() {
		return roboticCook;
	}

	public void setRoboticCook(RoboticState roboticCook) {
		this.roboticCook = roboticCook;
	}

	public RoboticState getRoboticOff() {
		return roboticOff;
	}

	public void setRoboticOff(RoboticState roboticOff) {
		this.roboticOff = roboticOff;
	}

	public RoboticState getState() {
		return state;
	}

	public void setState(RoboticState state) {
		this.state = state;
	}

	public RoboticState getRoboticStandby() {
		return roboticStandby;
	}

	public void setRoboticStandby(RoboticState roboticStandby) {
		this.roboticStandby = roboticStandby;
	}

}
package com.javacodegeeks.patterns.statepattern;

public class RoboticStandby implements RoboticState{

private final Robot robot;

	public RoboticStandby(Robot robot){
		this.robot = robot;
	}

	@Override
	public void walk() {
		System.out.println("In standby state...");
		robot.setState(robot.getRoboticOn());
		System.out.println("Walking...");
	}

	@Override
	public void cook() {
		System.out.println("In standby state...");
		robot.setRoboticState(robot.getRoboticCook());
		System.out.println("Cooking...");
	}

	@Override
	public void off() {
		System.out.println("In standby state...");
		robot.setState(robot.getRoboticOff());
		System.out.println("Robot is switched off");

	}

}

现在,以上代码更改将导致以下输出:

Walking...
In standby state...
Cooking...
In standby state...
Walking...
In standby state...
Robot is switched off
Walking...
In standby state...
Robot is switched off
Cannot cook at Off state.

4.何时使用状态设计模式

在以下两种情况下,请使用State模式:

  • 对象的行为取决于其状态,并且它必须在运行时根据该状态更改其行为。
  • 操作具有取决于对象状态的大型,多部分条件语句。 此状态通常由一个或多个枚举常量表示。 通常,几个操作将包含此相同的条件结构。 State模式将条件的每个分支放在单独的类中。 这样一来,您就可以将对象的状态视为独立于其他对象而独立变化的对象。

5. Java中的状态设计模式

  • javax.faces.lifecycle.LifeCycle#execute()

6.下载源代码

这是关于状态设计模式的课程。 您可以在此处下载源代码: StatePattern-Project

翻译自: https://www.javacodegeeks.com/2015/09/state-design-pattern.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值