C#设计模式之10:状态模式
状态模式
状态模式将合适的Context(上下文)模拟成一个状态机,在这个状态机的内部,由Context来决定整个状态机的状态,再根据不同的状态执行不同的方法。在C#编译器的帮助下,很多语法糖的背后都是一个状态机的实现,比如在一个返回IEnumerale或者IEnumeartor的方法中使用yield return,就会在后面建立一个状态机,再比如await一个可等待(或者说实现了GetAwaiter方法的类型,比如Task)的类型的时候,编译器也会在后台建立一个状态机类来根据state字段的不同的值来执行不同的逻辑。
状态模式的UML于策略模式相似(strategy patern):

不同之处在于他们的意图不同:策略模式需要客户(调用者)主动的去指定Context需要组合的策略对象是哪一个。而状态模式的策略对象(就是上图中的state)一般是固定在业务执行流程中的。
一般来说,我们把策略模式想象成除了继承之外的一种弹性替代方案,如果使用继承定义了一个类的行为,这种行为是静态编译时就确定的,你将被这个行为困住,甚至修改它都会很困难,有了策略模式,你可以通过组合不同的对象来改变行为,
我们把状态模式想成是不用在Context中放置很多if else条件判断的替代方案。通过将行为封装到不同的状态对象中,你可以通过在Context内简单的改变状态对象来改变Context的行为。
状态模式的定义:允许对象在内部状态改变时改变它的行为,对象看起来好像改变了它的类。
在C#的委托的帮助下,我们实现状态模式实际上可以用事件机制来进行实现。比如说某个类中有很多类似OnShitHappend方法这种的实现。这是我对这个模式的理解,但是还没有进行相应的实践。
先来看一下使用这个模式的一个背景,书上的讲的是糖果公司为了扩展业务,需要对糖果机进行扩展,并加入一些营销的手段,这个糖果机的使用流程是①投入硬币②转动摇杆③糖果从槽子里面出来:

从上图看以看出这个糖果机有几个状态:

如果不适用状态模式来实现这个糖果机的代码,那里面肯定是一堆if else的语句,这不是最糟糕的,最糟糕的是如果要加入额外的状态那就不得不重新考虑所有的逻辑,补充新的if else。。。是吧?
那直接来看使用状态模式实现的吧:
public interface IState
{
void InsertQuarter();
void EjectQuarter();
void TurnCrank();
void Dispense();
}
首先定义一个IState的接口,这个接口定义了糖果机内部的所有动作。因为糖果机在这里被模拟成一个状态机,这个状态机的状态的改变都是根据不同动作的执行来连带的。
public class GumballMachine
{
public IState NOquarterState { get; set; }
public IState SoldOutState { get; set; }
public IState HasQuarterState { get; set; }
public IState SoldState { get; set; }
public IState WinnerState { get; set; }
public IState State { get; set; }
public int Count { get; set; } public GumballMachine(int numberGumballs)
{
SoldOutState = new SoldOutState(this);
NOquarterState = new NoQuarterState(this);
HasQuarterState = new HasQuarterState(this);
SoldState = new SoldState(this);
WinnerState=new WinnerState(this);
State = NOquarterState;
Count = numberGumballs;
} public void InsertQuarter()
{
State.InsertQuarter();
} public void EjectQuarter()
{
State.EjectQuarter();
}
public void TrunCrank()
{
State.TurnCrank();
State.Dispense();
}
public void ReleaseBall()
{
Console.WriteLine("a gumball come rolling out the slot");
if (Count!=)
{
Count--;
}
}
}
然后定义这个糖果机。在糖果机内部有很多不同的状态,状态会根据执行不同的方法而改变。
然后定义这些状态:首先定义没有投入硬币的状态对象。糖果机的初始状态就是这个状态。
public class NoQuarterState : IState
{
private readonly GumballMachine _gumballMachine; public NoQuarterState(GumballMachine gumballMachine)
{
_gumballMachine = gumballMachine;
}
public void InsertQuarter()
{
Console.WriteLine("now you insert a quarter!");
_gumballMachine.State = _gumballMachine.HasQuarterState;
} public void EjectQuarter()
{
Console.WriteLine("you have not inserted a quarter!");
} public void TurnCrank()
{
Console.WriteLine("you turned ,but there is not a quarter!");
} public void Dispense()
{
Console.WriteLine("you need to pay first!");
}
}
投入硬币后就会进入有硬币的状态:
public class HasQuarterState : IState
{
private readonly GumballMachine _gumballMachine;
public HasQuarterState(GumballMachine gumballMachine)
{
_gumballMachine = gumballMachine;
}
public void InsertQuarter()
{
Console.WriteLine("you can not insert another quarter!");
} public void EjectQuarter()
{
Console.WriteLine("quarter's returned");
_gumballMachine.State = _gumballMachine.NOquarterState;
} public void TurnCrank()
{
Console.WriteLine("you turned...");
int winner=new Random().Next(,);
if (winner==&&_gumballMachine.Count>)
{
_gumballMachine.State = _gumballMachine.WinnerState;
}
else
{
_gumballMachine.State = _gumballMachine.SoldState;
}
} public void Dispense()
{
Console.WriteLine("no gumball dispensed!");
}
}
硬币投进去后紧接着就会转动摇杆,然后就会进入售卖状态:
public class SoldState : IState
{
private readonly GumballMachine _gumballMachine; public SoldState(GumballMachine gumballMachine)
{
_gumballMachine = gumballMachine;
}
public void InsertQuarter()
{
Console.WriteLine("please wait,we're already turned the crank!");
} public void EjectQuarter()
{
Console.WriteLine("sorry,we are already turned the crank!");
} public void TurnCrank()
{
Console.WriteLine("turning twice dose not give you another gumball!");
} public void Dispense()
{
_gumballMachine.ReleaseBall();
if ((_gumballMachine.Count>))
{
_gumballMachine.State = _gumballMachine.NOquarterState;
}
else
{
Console.WriteLine("opps,out of gumballs!");
_gumballMachine.State = _gumballMachine.SoldOutState;
}
}
}
在售卖状态,要做的就是糖果从槽子里面出来,当糖果出来后,我们要进行一些判断:如果还有糖果,接下来我们就进入初始状态,就是NoQuarterState状态,如果没有糖果,就会进入售完状态:
public class SoldOutState : IState
{
private readonly GumballMachine _gumballMachine; public SoldOutState(GumballMachine gumballMachine)
{
_gumballMachine = gumballMachine;
}
public void InsertQuarter()
{
Console.WriteLine("sorry,the gumballMachine's sold out!");
_gumballMachine.State = _gumballMachine.HasQuarterState;
} public void EjectQuarter()
{
Console.WriteLine("now return your quarter!");
_gumballMachine.State = _gumballMachine.NOquarterState;
} public void TurnCrank()
{
Console.WriteLine("sorry,the gumballmachine's sold out!");
} public void Dispense()
{
Console.WriteLine("sorry,,the gumbalmachine's sold out!");
}
}
当我们需要开展一些营销活动时,可以扩展IState接口,来创建一个营销类:
public class WinnerState:IState
{
private readonly GumballMachine _gumballMachine;
public WinnerState(GumballMachine gumallMachine)
{
_gumballMachine = gumallMachine;
}
public void InsertQuarter()
{
Console.WriteLine("invalid operation..");
} public void EjectQuarter()
{
Console.WriteLine("invalid operation..");
} public void TurnCrank()
{
Console.WriteLine("invliad operation..");
} public void Dispense()
{
Console.WriteLine("congratulations!you are the winner!you'll get two gumballs with one quarter!");
_gumballMachine.ReleaseBall();
if (_gumballMachine.Count==)
{
_gumballMachine.State = _gumballMachine.SoldOutState;
}
else
{
_gumballMachine.ReleaseBall();
if (_gumballMachine.Count >)
{
_gumballMachine.State = _gumballMachine.NOquarterState;
}
else
{
Console.WriteLine("out of gumballs!");
_gumballMachine.State = _gumballMachine.SoldOutState;
}
}
}
}
这个winnerstate类可以在转动摇杆的逻辑中放入。具体参见上面的HasQuarterState类。
C#设计模式之10:状态模式的更多相关文章
- 【HeadFirst设计模式】10.状态模式
定义: 允许对象在内部状态改变时改变它 行为,对象看起来好像修改了它的类. OO原则: 封装变化 多用组合,少用继承 针对接口编程,不针对实现编程 为交互对象之间的松耦合设计而努力 类应该对扩展开放, ...
- Head First 设计模式 --10 状态模式
状态模式:允许对象在内部状态改变时改变他的行为,对象看起来好像修改了他的类. 用到的设计原则1.封装变化2.多用组合,少用继承3.针对接口编程,不针对实现编程4.松耦合5.对扩展开放,对修改关闭6.依 ...
- Java设计模式系列之状态模式
状态模式(State)的定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它 ...
- Java设计模式学习记录-状态模式
前言 状态模式是一种行为模式,用于解决系统中复杂的对象状态转换以及各个状态下的封装等问题.状态模式是将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象的状态可以灵活多变.这样在客户端使 ...
- java设计模式-----22、状态模式
概念: State模式也叫状态模式,是行为设计模式的一种.State模式允许通过改变对象的内部状态而改变对象的行为,这个对象表现得就好像修改了它的类一样. 根据这个概念,我们举个例子 public c ...
- 《Java设计模式》之状态模式
状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式. 状态模式同意一个对象在其内部状态改变的时候改变其行为.这个对象看上去就像是改变了它 ...
- JAVA设计模式之【状态模式】
状态模式 水.固态.气态.液态 账户.正常状态.透支状态.受限状态 状态模式中,用一个状态类来分散冗长的条件语句,让系统有灵活性和可扩展性 状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的 ...
- 大话设计模式Python实现-状态模式
状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类 下面是一个状态模式的demo: #!/usr/bin/env python # -*- ...
- 重学 Java 设计模式:实战状态模式「模拟系统营销活动,状态流程审核发布上线场景」
作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! @ 目录 一.前言 二.开发环境 三.状态模式介绍 四.案例场景模拟 1 ...
- C#设计模式系列:状态模式(State)
1.状态模式简介 1.1>.定义 状态模式的核心思想是允许一个对象在它的内部状态改变时改变它的行为,即不同的状态对应不同的行为. 状态模式的针对性很强,当有状态变化的时候可以选择状态模式. 1. ...
随机推荐
- Should we ban guns 英语禁枪议论文
Should we ban guns ? 我们应该禁枪吗? 英语议论文 Should we ban guns? Author:Pleiades_Antares(www.cnblogs.com/iris ...
- 强化学习(一)—— 基本概念及马尔科夫决策过程(MDP)
1.策略与环境模型 强化学习是继监督学习和无监督学习之后的第三种机器学习方法.强化学习的整个过程如下图所示: 具体的过程可以分解为三个步骤: 1)根据当前的状态 $s_t$ 选择要执行的动作 $ a_ ...
- D. Zero Quantity Maximization(hash+map)
题意:就是让c=a*x+b,给你一个a[],b[],让你尽可能多的让c[]=0,输出有多少. 思路:直接令c=0,则x=-b/a, 也就是一条直线,通过这样就用hash值使相同的k值映射到一起,使用了 ...
- windows server 2012 安装 VC14(VC2015) 安装失败解决方案
原文地址:https://www.cnblogs.com/huoniao/articles/6186021.html 系统环境如下:cmd命令行-输入 systeminfo 如下图 - The VC1 ...
- ③---Java项目管理工具MAVEN安装与配置
Java项目管理工具MAVEN安装配置以下将为大家介绍Java项目管理工具MAVEN安装及其配置. 一.下载MAVEN安装文件 maven下载地址:https://maven.apache.org/d ...
- Luogu 3793 由乃救爷爷
\(\verb|Luogu 3793 由乃救爷爷|\) rmq,数据随机 \(n,\ m\leq 2\times10^7\) lxl ST表 分块,大小设为 \(x\) 预处理每个块两端到块内每个点的 ...
- selenium:解决页面元素display:none的方法
在UI自动化测试中,有时候会遇到页面元素无法定位的问题,包括xpath等方法都无法定位,是因为前端元素被设置为不可见导致. 这篇博客,介绍下如何通过JavaScript修改页面元素属性来定位的方法.. ...
- Python 中的 10 个常见安全漏洞,以及如何避免(上)
简评:编写安全代码很困难,当你学习一个编程语言.模块或框架时,你会学习其使用方法. 在考虑安全性时,你需要考虑如何避免被滥用,Python 也不例外,即使在标准库中,也存在用于编写应用的不良实践.然而 ...
- PHP中静态变量和函数引用返回
这两天看看PHP写的框架CI,源代码中写了很多静态变量和函数引用. 官方文档地址:http://php.net/manual/zh/language.references.return.php 简单写 ...
- odoo常用widget
widget=”statusbar” 头部状态条标签widget=”email” 电子邮件地址标签widget=”selection” 下拉选择标签widget=”mail_followers” ...