JAVA设计模式之状态模式

一、状态模式简介

State模式也叫状态模式,是行为设计模式的一种。State模式允许通过改变对象的内部状态而改变对象的行为,这个对象表现得就好像修改了它的类一样。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转译到表现不同状态的一系列类当中,可以把复杂的判断逻辑简化。

二、状态模式的结构

在这里插入图片描述

三、状态模式的角色与职责

  • Context:用户对象拥有一个State类型的成员,以标识对象的当前状态;
  • State:接口或基类封装与Context的特定状态相关的为;
  • ConcreteState:接口实现类或子类实现了一个与Context某个状态相关的行为。

四、状态模式的具体实现

糖果公司想要设计一个糖果机器,现在需要我们上场啦。

1、不使用状态模式

不加思索地,我们就有了第一个方案。

方案设计
Candymachine---
域(表示糖果机的四个状态)Sold_outNo_quarterHas_quarterSlod
方法(四个方法,分别对应不同状态下的反应)insertQuarter()ejectQuarter()turnCrank()dispense()

接下来就是实现简单的糖果机器了。

类设计
// An highlighted block
package design.state.gys.nostate;
public class Candymachine {
 final static int Sold_out=0;
 final static int No_quarter=1;
 final static int Has_quarter=2;
 final static int Sold=3;
 int state=Sold_out;
 int count=0;
 public Candymachine(int count) {
  super();
  this.count = count;
  if(this.count>0)
   this.state=No_quarter;
 }
 public void insertQuarter() {
  if(state==Sold_out)
   System.out.println("全部售出,无法放入硬币");
  else if(state==No_quarter) {
   System.out.println("投入硬币");
   state=Has_quarter;
  }
  else if(state==Has_quarter)
   System.out.println("已投入硬币,转动摇杆吧");
  else if(state==Sold)
   System.out.println("正在出售糖果,稍后...");
 }
 public void ejectQuarter() {
  if(state==Sold_out)
   System.out.println("全部售出,无法购买");
  else if(state==No_quarter)
   System.out.println("请投入硬币");
  else if(state==Has_quarter) {
   System.out.println("已退出硬币");
   state=No_quarter;
  }
  else if(state==Sold)
   System.out.println("正在出售糖果,无法退币");
  }
 public void turnCrank() {
  if(state==Sold_out)
   System.out.println("全部售出,无法购买");
  else if(state==No_quarter)
   System.out.println("请投入硬币");
  else if(state==Has_quarter) {
   System.out.println("已投入硬币,转动摇杆吧");
   state=Sold;
   dispense();
  }
  else if(state==Sold) 
   System.out.println("已掉落糖果,无法再次掉落");
 }
 public void dispense() {
  if(state==Sold) {
  System.out.println("糖果掉落");
  count--;
  if(count==0)
   state=Sold_out;
  else 
   state=No_quarter;
  }
  else if (state==No_quarter) {
   System.out.println("请投入硬币");
  }else if(state==Sold_out) {
   System.out.println("全部售出,无法购买");
  }else {
   System.out.println("请先转动摇杆");
  }
 }
}

大量的slse if语句充斥着代码,先不管这些,来看看是否能运行吧。

// An highlighted block
package design.state.gys.nostate;
public class Test {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  Candymachine cm=new Candymachine(5);
  cm.turnCrank();
  cm.insertQuarter();
  cm.ejectQuarter();
  cm.insertQuarter();
  cm.turnCrank();
  cm.turnCrank();
  cm.ejectQuarter();
 }
}

屏住呼吸,看看验收情况:

// An highlighted block
请投入硬币
投入硬币
已退出硬币
投入硬币
已投入硬币,转动摇杆吧
糖果掉落
请投入硬币
请投入硬币

糖果公司的老板还算满意,但是她希望我们能够设计出更好一些的糖果机器,便于扩展接入。

2、使用状态模式

现在,我们为机器的每一个状态都定义一个类,用于封装每个动作下的反应,当动作发生时,委托给现在的状态进行处理。

方案设计

在这里插入图片描述

类设计

首先我们定义一个状态接口。

// An highlighted block
package design.state.gys.state;
public interface State {
 void insertQuuarter();
 void ejectQuarter();
 void turnCrack();
 void dispense();
}

接下来就是定义我们所需要的四个状态,这些类将负责在对应状态下的动作执行,并且在每个状态的构造器内传入糖果机器以便获取状态:
Sold:

// An highlighted block
package design.state.gys.state;
public class Sold implements State{
 CandyMachine cm;
 public Sold(CandyMachine cm) {
  super();
  this.cm = cm;
 }
 @Override
 public void insertQuuarter() {
  // TODO Auto-generated method stub
  System.out.println("请稍等,正在掉落糖果");
 }
 @Override
 public void ejectQuarter() {
  // TODO Auto-generated method stub
  System.out.println("正在掉落糖果,无法退币");
 }
 @Override
 public void turnCrack() {
  // TODO Auto-generated method stub
  System.out.println("已经转动摇杆,无法再转");
 }
 @Override
 public void dispense() {
  // TODO Auto-generated method stub
  cm.releaseBall();
  if(cm.count>0)
   cm.setState(cm.getNoquarter());
  else {
   System.out.println("全部售完");
   cm.setState(cm.getSoleout());
  }
 }
}

Soldout:

// An highlighted block
package design.state.gys.state;
public class Soldout implements State{
CandyMachine cm;
 public Soldout(CandyMachine cm) {
  super();
  this.cm = cm;
 }
 @Override
 public void insertQuuarter() {
  // TODO Auto-generated method stub
  System.out.println("已售完,无法投币");
 }
 @Override
 public void ejectQuarter() {
  // TODO Auto-generated method stub
  System.out.println("未投币,无法退币");
 }
 @Override
 public void turnCrack() {
  // TODO Auto-generated method stub
  System.out.println("已售完");
 }
 @Override
 public void dispense() {
  // TODO Auto-generated method stub
  System.out.println("已售完");
 }
}

HasQuatrer:

// An highlighted block
package design.state.gys.state;
public class HasQuarter implements State{
CandyMachine cm;
 public HasQuarter(CandyMachine cm) {
  super();
  this.cm = cm;
 }
 @Override
 public void insertQuuarter() {
  // TODO Auto-generated method stub
  System.out.println("已经投入硬币,转动摇杆吧");
 }
 @Override
 public void ejectQuarter() {
  // TODO Auto-generated method stub
  System.out.println("正在退币");
  cm.setState(cm.getNoquarter());
 }
 @Override
 public void turnCrack() {
  // TODO Auto-generated method stub
  System.out.println("转动摇杆,请稍后");
  cm.setState(cm.getSold());
 }
 @Override
 public void dispense() {
  // TODO Auto-generated method stub
  System.out.println("转动摇杆吧");
 }
}

NoQuarter:

// An highlighted block
package design.state.gys.state;
public class NoQuarter implements State{
 CandyMachine cm;
 public NoQuarter(CandyMachine cm) {
  super();
  this.cm = cm;
 }
 @Override
 public void insertQuuarter() {
  // TODO Auto-generated method stub
  System.out.println("投入硬币");
  cm.setState(cm.getHasquarter());
 }
 @Override
 public void ejectQuarter() {
  // TODO Auto-generated method stub
  System.out.println("未投入硬币,无法退币");
 }
 @Override
 public void turnCrack() {
  // TODO Auto-generated method stub
  System.out.println("未投入硬币,无法摇动摇杆");
 }
 @Override
 public void dispense() {
  // TODO Auto-generated method stub
  System.out.println("请投入硬币");
 }
}

状态类定义完成,接下来事糖果机的设计了:

// An highlighted block
package design.state.gys.state;
public class CandyMachine {
 State sold;
 State noquarter;
 State hasquarter;
 State soleout;
 State state=null;
 int count =0;
 public CandyMachine(int count) {
  super();
  this.count = count;
  sold=new Sold(this);
  noquarter=new NoQuarter(this);
  hasquarter=new HasQuarter(this);
  soleout=new Sold(this);
  if(count>0)
   state=noquarter;
 }
 public void insertQuuarter() {
  state.insertQuuarter();
 }
 public void ejectQuarter() {
  state.ejectQuarter();
 }
 public void turnCrack() {
 state.turnCrack();
 if(state==sold)
  state.dispense();
 }
 void setState(State state) {
  this.state=state;
 }
 void releaseBall() {
  System.out.println("掉落糖果");
  if(count!=0)
   count--;
 }
 public State getSold() {
  return sold;
 }
 public State getNoquarter() {
  return noquarter;
 }
 public State getHasquarter() {
  return hasquarter;
 }
 public State getSoleout() {
  return soleout;
 }
 public int getCount() {
  return count;
 }
}

貌似比上次的设计轻松多了,并且我们增加了其他的功能,可以查询糖果机的状态、设置状态等,并且更加容易进行扩展状态,只需要实现State接口,并将状态加入就,行。
废话不多说,是时候拉出来溜溜了:

// An highlighted block
package design.state.gys.state;
public class Test {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  CandyMachine cm=new CandyMachine(5);
  cm.insertQuuarter();
  cm.ejectQuarter();
  cm.insertQuuarter();
  cm.insertQuuarter();
  cm.turnCrack();
  cm.turnCrack();
 }
}

看看结果吧:

// An highlighted block
投入硬币
正在退币
投入硬币
已经投入硬币,转动摇杆吧
转动摇杆,请稍后
掉落糖果
未投入硬币,无法摇动摇杆

一样实现了原来的功能。好了,圆满完成了公司的任务。

五、状态模式和策略模式、模板方法模式的区别

  1. 策略模式在传入对象之后不会改变,而状态模式在运行中会根据状态不同而改变不同的行为。策略模式可以作为状态模式的基础。
  2. 模板模式的每一个类都只是整个算法的一部分,而状态模式则是完整的一个结构。

要抱抱才会开心呀~~~~~~~~~~~~

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值