【状态模式】 State Pattern

时间:2022-09-14 15:17:05

我们先设计一个场景,饮料自动售卖机,来设计一下它的出售流程。

【状态模式】 State Pattern

流程图中,我们可把这个过程看成几个状态: 投币状态,选择饮料状态,售出状态,出售完毕状态.

,有了这个四个状态,我们设计一下界面(很粗略):

【状态模式】 State Pattern

在这里我们只定义了三种饮料和一个投币口,在设计接口和类之前,我们来看一下状态模式的UML图:

【状态模式】 State Pattern

State接口定义了一个所有具体状态的共同接口;任何状态都实现这个相同的接口,这样一来,状态之间可以互相代替.

ConcreteState(具体状态)处理来自Context请求。每一个ConcreteState都提供了它自己对于请求的实现。所以,当Context改变状态时行为也跟着改变。

Context(上下文)是一个类,它可以拥有一些内部状态。

根据成熟的状态模式UML图,我们来设计我们自己的UML类图:

【状态模式】 State Pattern

直接上代码(可能和UML图有些出入,多了些参数,图主要是搭出一个架构来)

实体类:

  public class SoftDrink
{
public string Name { get; set; }
public int Price { get; set; } public int Count { get; set; } private SoftdrinkMachineContext _context = new SoftdrinkMachineContext(); public SoftdrinkMachineContext Context
{
get { return _context; }
}
}

创建获取某种饮料的工厂:

 public class SoftDrinkFactory
{
public static SoftDrink GetSoftDrink(string softDrinkName)
{
SoftDrink softDrink = SoftDrinkRepository.SoftDrinks.SingleOrDefault(s => s.Name.Equals(softDrinkName)); if (softDrink == null)
throw new ArgumentException(string.Format("没有该饮料:{0}", softDrinkName)); return softDrink;
}
}

饮料的存储库

 public class SoftDrinkRepository
{ static SoftDrinkRepository()
{
SoftDrinks = new List<SoftDrink>();
AddSoftDrink(new SoftDrink { Name = "可乐", Count = , Price = });
AddSoftDrink(new SoftDrink { Name = "果粒橙", Count = , Price = });
AddSoftDrink(new SoftDrink { Name = "咖啡", Count = , Price = });
} public static List<SoftDrink> SoftDrinks { get; private set; } public static void AddSoftDrink(SoftDrink softDrink)
{
if (SoftDrinks.Any(s => s.Name.Equals(softDrink.Name)))
{
SoftDrink needtobeAddedSoftdrink = SoftDrinks.Single(s => s.Name.Equals(softDrink.Name)); needtobeAddedSoftdrink.Price = softDrink.Price;
needtobeAddedSoftdrink.Count = softDrink.Count;
} SoftDrinks.Add(softDrink);
}
}

这里存钱的地方,相当于一个银行,用的是静态

  public class Constants
{
public static int StoredMoney { get; set; }
}

接口:

 public interface ISoftdrinkState
{
void InsertQuarter();
void SelectSoftdrink(SoftDrink softDrink);
void Dispense(SoftDrink softDrink);
void SoldOut();
}

这里的四个实现类代表四种状态,整个状态切换由内部自动完成.

public abstract class AbstractSoftdrinkMacheState : ISoftdrinkState
{
protected SoftdrinkMachineContext _softdrinkMachineContext; protected AbstractSoftdrinkMacheState(SoftdrinkMachineContext softdrinkMachineContext)
{ _softdrinkMachineContext = softdrinkMachineContext;
} public abstract void InsertQuarter();
public abstract void SelectSoftdrink(SoftDrink softDrink);
public abstract void Dispense(SoftDrink softDrink);
public abstract void SoldOut(); } public class NoQuarterState : AbstractSoftdrinkMacheState
{
public NoQuarterState(SoftdrinkMachineContext softdrinkMachineContext)
: base(softdrinkMachineContext)
{
} public override void InsertQuarter()
{
_softdrinkMachineContext.SetState(_softdrinkMachineContext.HasQuarterState); } public override void SelectSoftdrink(SoftDrink softDrink)
{
throw new InvalidOperationException("你需要先投币");
} public override void Dispense(SoftDrink softDrink)
{
throw new InvalidOperationException("你需要先投币");
} public override void SoldOut()
{
throw new InvalidOperationException("你需要先投币");
}
} public class HasQuarterState : AbstractSoftdrinkMacheState
{
public HasQuarterState(SoftdrinkMachineContext softdrinkMachineContext)
: base(softdrinkMachineContext)
{
} public override void InsertQuarter()
{ } public override void SelectSoftdrink(SoftDrink softDrink)
{
if (softDrink.Price > Constants.StoredMoney)
throw new InvalidOperationException("钱不够,请重新选择或补足");
_softdrinkMachineContext.SetState(_softdrinkMachineContext.SoldState); } public override void Dispense(SoftDrink softDrink)
{
throw new InvalidOperationException("你需要先选择饮料");
} public override void SoldOut()
{
throw new InvalidOperationException("你需要先选择饮料");
}
} public class SoldState : AbstractSoftdrinkMacheState
{
public SoldState(SoftdrinkMachineContext softdrinkMachineContext)
: base(softdrinkMachineContext)
{
} public override void InsertQuarter()
{
throw new InvalidOperationException("请点击选择完毕按");
} public override void SelectSoftdrink(SoftDrink softDrink)
{
throw new InvalidOperationException("请点击选择完毕按");
} public override void Dispense(SoftDrink softDrink)
{
softDrink.Count--;
Constants.StoredMoney -= softDrink.Price;
_softdrinkMachineContext.SetState(softDrink.Count > 0
? _softdrinkMachineContext.NoQuarterState
: _softdrinkMachineContext.SoldOutState);
} public override void SoldOut()
{
throw new InvalidOperationException("请点击选择完毕按");
}
} public class SoldOutState : AbstractSoftdrinkMacheState
{
public SoldOutState(SoftdrinkMachineContext softdrinkMachineContext)
: base(softdrinkMachineContext)
{
} public override void InsertQuarter()
{ } public override void SelectSoftdrink(SoftDrink softDrink)
{
throw new InvalidOperationException("已经售完");
} public override void Dispense(SoftDrink softDrink)
{
throw new InvalidOperationException("已经售完");
} public override void SoldOut()
{
throw new InvalidOperationException("已经售完");
}
}

上下文Context

public class SoftdrinkMachineContext
{
private ISoftdrinkState _state; public SoftdrinkMachineContext()
{
NoQuarterState = new NoQuarterState(this);
SoldOutState = new SoldOutState(this);
HasQuarterState = new HasQuarterState(this);
SoldState = new SoldState(this); _state = NoQuarterState;
} public ISoftdrinkState SoldOutState { get; private set; }
public ISoftdrinkState NoQuarterState { get; private set; }
public ISoftdrinkState HasQuarterState { get; private set; }
public ISoftdrinkState SoldState { get; private set; } public void InsertQuarter()
{
_state.InsertQuarter(); } public void SelectSoftdrink(SoftDrink softDrink)
{
_state.SelectSoftdrink(softDrink);
} public void Dispense(SoftDrink softDrink)
{
_state.Dispense(softDrink);
} public void SoldOut()
{
_state.SoldOut();
} public void SetState(ISoftdrinkState state)
{
_state = state;
}
}

Form窗口类

public partial class Form1 : Form
{
private SoftDrink _currSoftDrink; public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
ActionWithAlertingErrorInfo(() =>
{
_currSoftDrink.Context.Dispense(_currSoftDrink);
MessageBox.Show(string.Format("退出{0}钱", Constants.StoredMoney));
Constants.StoredMoney = ;
}); } private void btnInputMoney_Click(object sender, EventArgs e)
{
var money = ;
if (int.TryParse(txtMoneyInput.Text, out money))
{
Constants.StoredMoney += money;
ActionWithAlertingErrorInfo(() => SoftDrinkRepository.SoftDrinks.ForEach(c => c.Context.InsertQuarter()));
}
} private void btnCoke_Click(object sender, EventArgs e)
{
var btn = sender as Button;
var index = btn.Text.IndexOf("(", StringComparison.Ordinal);
var softDrinkName = btn.Text.Substring(, index); _currSoftDrink = SoftDrinkFactory.GetSoftDrink(softDrinkName); ActionWithAlertingErrorInfo(() => _currSoftDrink.Context.SelectSoftdrink(_currSoftDrink));
} public void ActionWithAlertingErrorInfo(Action action)
{
try
{
action.Invoke();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

这里加入了一个Softdrink类,因为由于每一种饮料都有自己的状态,所以对每个饮料都要有一个上下文的类。

后记:

最近一个朋友告诉我,她怎么都觉得策略模式和状态模式是一样,既然名字不一样,功能肯定不一样,该去怎么区分。

策略模式和状态模式可以说是同胞兄弟,但是本质还是有些区别.

  策略模式->定义算法族,分别封装起来,让它们之间可以互相替换(手动),此模式让算法的变化独立于使用算法的客户。

  状态模式->允许对象在内部状态改变时改变它的行为(自动),对象看来好像修改了它的类。

也就是说,状态模式利用许多不同的状态对象,当Context对象随着时间而改变装,而任何的状态改变都是定义好的。换句话说,“改变行为”这件事是建立在我状态模式自己方案中的,而策略模式并没有一组状态标记,而更多由调用者去使用。

【状态模式】 State Pattern的更多相关文章

  1. 二十四种设计模式:状态模式&lpar;State Pattern&rpar;

    状态模式(State Pattern) 介绍允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它所属的类. 示例有一个Message实体类,对它的操作有Insert()和Get()方法, ...

  2. 乐在其中设计模式&lpar;C&num;&rpar; - 状态模式&lpar;State Pattern&rpar;

    原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...

  3. 状态模式-State Pattern&lpar;Java实现&rpar;

    状态模式-State Pattern 在状态模式(State Pattern)中,类的行为是基于它的状态改变的.当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. State接口 ...

  4. 设计模式&lpar;十二&rpar;:通过ATM取款机来认识&OpenCurlyDoubleQuote;状态模式”&lpar;State Pattern&rpar;

    说到状态模式,如果你看过之前发布的重构系列的文章中的<代码重构(六):代码重构完整案例>这篇博客的话,那么你应该对“状态模式”并不陌生,因为我们之前使用到了状态模式进行重构.上一篇博客我们 ...

  5. 十一个行为模式之状态模式&lpar;State Pattern&rpar;

    定义: 当一个对象有多个状态,并且在每个状态下有不同的行为,可以使用状态模式来在其内部改变状态时改变其行为,而客户端不会察觉状态的改变,仍使用同样的方法或接口与对象进行交互. 结构图: Context ...

  6. 【UE4 设计模式】状态模式 State Pattern

    概述 描述 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类. 其别名为状态对象(Objects for States),状态模式是一种对象行为型模式. 有限状态机(FSMs) ...

  7. 状态模式&lpar;State Pattern&rpar;

    当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂 ...

  8. C&num;设计模式——状态模式&lpar;State Pattern&rpar;

    一.概述在面向对象软件设计时,常常碰到某一个对象由于状态的不同而有不同的行为.如果用if else或是switch case等方法处理,对象操作及对象的状态就耦合在一起,碰到复杂的情况就会造成代码结构 ...

  9. &lbrack;设计模式&rsqb; 20 状态模式 State Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对状态模式是这样说的:允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它的类.状态模式的重点在于状态转换,很多时候,对 ...

  10. php状态模式&lpar;state pattern&rpar;

    ... <?php /* The state pattern encapsulates the varying behavior for the same object based on its ...

随机推荐

  1. 关于安卓6&period;0权限申请 PermissionDog

    最近在一家公司实习,项目中需要用到适配安卓6.0以上的系统,我本来是想用其他人已经写好的权限申请框架来实现的,但是发现跟我的需求有点小区别,所以就自己写了一个 这个权限申请的帮助类很小,只有一个jav ...

  2. UML的目标

    http://zhidao.baidu.com/link?url=ghQvzG70vSCSLyQcrHDTd7xt1aSWBR73lPIMxBCEPo1ktkq9cQ3EE9TXX1mZyHINkVA ...

  3. C&num; 事务处理

    前言: 通常SqlHelper类为了方便处理,做成了静态类,静态类的问题是不方便添加事务处理. 实例化类方便添加事务处理,DoTrans/CommitTrans/RollBackTrans  三个函数 ...

  4. 【HDU】4908 &lpar;杭电 BC &num;3 1002题)BestCoder Sequence ——哈希

    BestCoder Sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  5. LaTeX中表格多行显示的最简单设置方法

    这事实上是一个非常easy的问题,可是这两天发现我之前的解决方式太麻烦了.简介一下这样的最简单的方法: 之前设置多行显示的时候,用类似于以下这样的方法进行多行显示: \begin{table} \ne ...

  6. ArcCore重构-生成&percnt;&lowbar;offset&period;h文件

    基于官方arc-stable-9c57d86f66be,AUTOSAR版本3.1.5 基本问题   ArcCore中,需要生成asm_offset.h和arch_offset.h这两个头文件,定义着代 ...

  7. 提升node&period;js中使用redis的性能

    问题初现 某基于node.js开发的业务系统向外提供了一个dubbo服务,提供向第三方缓存查询.设置多项业务数据并聚合操作结果.在QPS达到800时(两台虚拟机,每台机器4Core8G4node进程) ...

  8. a标签中的onclick和href的使用

    onclick和href 链接的 onclick 事件被先执行,其次是 href 属性下的动作(页面跳转,或 javascript 伪链接):  假设链接中同时存在 href 与 onclick,如果 ...

  9. Buildroot Savedefconfig

    /********************************************************************************* * Buildroot Saved ...

  10. js对象的几种创建方式和js实现继承的方式&lbrack;转&rsqb;

    一.js对象的创建方式 1. 使用Object构造函数来创建一个对象,下面代码创建了一个person对象,并用两种方式打印出了Name的属性值. var person = new Object(); ...