状态模式

假设某人一整天的流程就是“吃饭→工作→睡觉”,并且他要严格按照这个流程来,那也就是说在吃饭状态下,他只能做跟吃饭有关的事情,而不能越界做工作或者睡觉有关的事情,这就涉及到了状态的管理。在写代码的时候,我们常常要根据当前的状态,来决定下一个状态并且确定当前状态下要做什么样的事情。一般来讲,我们会写一系列的if-else if-else if-else语句来实现,但是要是状态非常多的时候,这种代码不仅仅看起来十分长,而且看的人生理上也会有一种厌恶感并且看一点估计忘一点。导致这种臭代码的原因就是,我们一口气在一个函数里面管理了太多种的状态。于是,有人就提出了,能不能让状态自己管理自己。也就有点像我们的行政制度中自治区,我们不再统一地在一个函数里面管理N种状态,而是让某个状态管理它自己本身。

经典的状态管理模式如下图所示

让我来解释一下这幅图的意思,IState依赖于IContext,也就是IContext对应的实体类拥有一个IState类型的字段,在IContext类里面的Request()方法里面调用IState中的Handle方法。我们可以通过改变IContext里面的IState实体类类型来改变状态,从而实现根据不同的状态使用不同的方法。

     下面让我们来段代码说明一下。以下代码模拟数据库的连接、关闭。连接和关闭两个状态分别有两个对应的状态类与之对应。

1、首先我们还是先定义状态的接口,另外定义一个抽象类,用来表示数据库连接类。

/// <summary>
    /// 数据库连接状态
    /// </summary>
    public interface IConnectionState
    {
        void Open();
        void Close();
        void Query();
    }

在定义一个数据库连接对象的抽象基类

abstract class ContextBase
    {

        private IConnectionState connectionState;

        public IConnectionState ConnectionState
        {
            get { return connectionState; }
            set { connectionState = value; }
        }

        public virtual void Open() { this.connectionState.Open(); }
        public virtual void Close() { this.connectionState.Close(); }
        public virtual void Query() { this.connectionState.Query(); }
    }

2、我们再定义两个具体类OpenState、CloseState,实现IConnectionState接口,分别代表数据库开、关两种状态。并且在状态类内部,如OpenState类的内部规定了在Opne状态下,可以执行的操作和不能够执行的操作。

/// <summary>
        /// 打开状态
        /// </summary>
        class OpenState : IConnectionState
        {

            public void Open()
            {
                throw new NotImplementedException("打开状态下,不能再打开数据库连接");
            }

            public void Close()
            {
                //打开状态下,可以关闭数据库连接
            }

            public void Query()
            {
                //打开状态下,可以查询
            }
        }
        /// <summary>
        /// 关闭状态
        /// </summary>
        class CloseState : IConnectionState
        {

            public void Open()
            {
                //关闭状态下可以重新打开连接
            }

            public void Close()
            {
                throw new NotImplementedException("关闭状态下,不能再关闭数据库连接");
            }

            public void Query()
            {
                throw new NotImplementedException("关闭状态下,不能查询数据库");
            }
        }

3、下面我们用一个类来继承抽象类,并进行测试。具体的类实现方式见下方,这里只给出关键函数。

public void ConnectionStateTest()
        {
            ContextBase target = CreateContextBase();
            target.ConnectionState = new OpenState();
            try
            {
                target.Open();//执行Open操作,遇到异常,不执行 Assert.IsTrue(false);
                Assert.IsTrue(false);
            }
            catch (Exception ex)
            {

            }
            target.Close();//在打开状态下,正常关闭,并执行Assert.IsTrue(false);
            Assert.IsTrue(false);

            target.ConnectionState = new CloseState();
            try
            {
                target.Close();
                Assert.IsTrue(false);
            }
            catch (Exception ex)
            {
            }

            target.Open();
            Assert.IsTrue(false);
        }

从以上代码,我们可以知道,原先需要用讨厌的if-else if-else if-else管理的讨厌的长长的状态管理函数,已经被我们封装在一个个的小状态管理类里面了,并且这些状态管理类可以自己管理自己什么状态应该做什么样的事情。

  1 using BangWorks.PractcalPattern.States.Classic;
  2 using Microsoft.VisualStudio.TestTools.UnitTesting;
  3 using System;
  4
  5 namespace BangWork.PractcalPattern.Concept.InderTest
  6 {
  7
  8
  9     /// <summary>
 10     ///这是 ContextBaseTest 的测试类,旨在
 11     ///包含所有 ContextBaseTest 单元测试
 12     ///</summary>
 13     [TestClass()]
 14     public class ContextBaseTest : ContextBase
 15     {
 16         /// <summary>
 17         /// 打开状态
 18         /// </summary>
 19         class OpenState : IConnectionState
 20         {
 21
 22             public void Open()
 23             {
 24                 throw new NotImplementedException("打开状态下,不能再打开数据库连接");
 25             }
 26
 27             public void Close()
 28             {
 29                 //打开状态下,可以关闭数据库连接
 30             }
 31
 32             public void Query()
 33             {
 34                 //打开状态下,可以查询
 35             }
 36         }
 37         /// <summary>
 38         /// 关闭状态
 39         /// </summary>
 40         class CloseState : IConnectionState
 41         {
 42
 43             public void Open()
 44             {
 45                 //关闭状态下可以重新打开连接
 46             }
 47
 48             public void Close()
 49             {
 50                 throw new NotImplementedException("关闭状态下,不能再关闭数据库连接");
 51             }
 52
 53             public void Query()
 54             {
 55                 throw new NotImplementedException("关闭状态下,不能查询数据库");
 56             }
 57         }
 58         private TestContext testContextInstance;
 59
 60         /// <summary>
 61         ///获取或设置测试上下文,上下文提供
 62         ///有关当前测试运行及其功能的信息。
 63         ///</summary>
 64         public TestContext TestContext
 65         {
 66             get
 67             {
 68                 return testContextInstance;
 69             }
 70             set
 71             {
 72                 testContextInstance = value;
 73             }
 74         }
 75
 76         #region 附加测试特性
 77         //
 78         //编写测试时,还可使用以下特性:
 79         //
 80         //使用 ClassInitialize 在运行类中的第一个测试前先运行代码
 81         //[ClassInitialize()]
 82         //public static void MyClassInitialize(TestContext testContext)
 83         //{
 84         //}
 85         //
 86         //使用 ClassCleanup 在运行完类中的所有测试后再运行代码
 87         //[ClassCleanup()]
 88         //public static void MyClassCleanup()
 89         //{
 90         //}
 91         //
 92         //使用 TestInitialize 在运行每个测试前先运行代码
 93         //[TestInitialize()]
 94         //public void MyTestInitialize()
 95         //{
 96         //}
 97         //
 98         //使用 TestCleanup 在运行完每个测试后运行代码
 99         //[TestCleanup()]
100         //public void MyTestCleanup()
101         //{
102         //}
103         //
104         #endregion
105
106
107         internal virtual ContextBase CreateContextBase()
108         {
109             // TODO: 实例化相应的具体类。
110             ContextBase target = new ContextBaseTest();
111             return target;
112         }
113
114         /// <summary>
115         ///Close 的测试
116         ///</summary>
117         [TestMethod()]
118         public void CloseTest()
119         {
120             ContextBase target = CreateContextBase(); // TODO: 初始化为适当的值
121             target.Close();
122             Assert.Inconclusive("无法验证不返回值的方法。");
123         }
124
125         /// <summary>
126         ///Open 的测试
127         ///</summary>
128         [TestMethod()]
129         public void OpenTest()
130         {
131             ContextBase target = CreateContextBase(); // TODO: 初始化为适当的值
132             target.Open();
133             Assert.Inconclusive("无法验证不返回值的方法。");
134         }
135
136         /// <summary>
137         ///Query 的测试
138         ///</summary>
139         [TestMethod()]
140         public void QueryTest()
141         {
142             ContextBase target = CreateContextBase(); // TODO: 初始化为适当的值
143             target.Query();
144             Assert.Inconclusive("无法验证不返回值的方法。");
145         }
146
147         /// <summary>
148         ///ConnectionState 的测试
149         ///</summary>
150         [TestMethod()]
151         public void ConnectionStateTest()
152         {
153             ContextBase target = CreateContextBase(); // TODO: 初始化为适当的值
154
155             target.ConnectionState = new OpenState();
156             try
157             {
158                 target.Open();//执行Open操作,遇到异常,不执行 Assert.IsTrue(false);
159                 Assert.IsTrue(false);
160             }
161             catch (Exception ex)
162             {
163
164             }
165             target.Close();//在打开状态下,正常关闭,并执行Assert.IsTrue(false);
166             Assert.IsTrue(false);
167
168             target.ConnectionState = new CloseState();
169             try
170             {
171                 target.Close();
172                 Assert.IsTrue(false);
173             }
174             catch (Exception ex)
175             {
176             }
177
178             target.Open();
179             Assert.IsTrue(false);
180         }
181     }
182 }

作者:kissazi2 
出处:http://www.cnblogs.com/kissazi2/ 
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载:http://www.cnblogs.com/kissazi2/p/3285879.html

时间: 2024-10-23 04:16:38

状态模式的相关文章

状态模式(state pattern) 详解

状态模式(state pattern): 允许对象在内部状态改变时改变它的行为, 对象看起来好像修改了它的类. 建立Context类, 包含多个具体状态(concrete state)类的组合, 根据状态的不同调用具体的方法, state.handle(), 包含set\get方法改变状态. 状态接口(state interface), 包含抽象方法handle(), 具体状态类(concrete state)继承(implement)状态类(state), 实现handle()方法; 具体方法

设计模式(8)-状态模式(关注状态之间的变化)

状态模式(State Pattern)是设计模式的一种,属于行为模式. 定义(源于Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化. 意图:允许一个对象在其内部状态改变时改变它的行为 适用场景: 1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为. 2.一个操作中含有庞大的多分

php设计模式 State (状态模式)

复制代码 代码如下: <?php /** * 状态模式 * * 允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它所属的类 * */ interface State { public function handle($state); public function display(); } class Context { private $_state = null; public function __construct($state) { $this->setState($

状态模式(state pattern) 未使用状态模式详解

状态模式可以控制状态的转换, 未使用设计模式时, 程序会非常繁杂. 具体方法: 1. 状态转换类. /** * @time 2014年7月11日 */ package state; /** * @author C.L.Wang * */ public class GumballMachine { final static int SOLD_OUT = 0; final static int NO_QUARTER = 1; final static int HAS_QUARTER = 2; fin

传统设计模式(十)状态模式

谈到状态模式我们在这里所谈论的是一个通用的技巧:如何对对象内的状态建模----通过创建一个实例变量来持有状态值,并在方法内书写条件代码来处理不同状态.我们要把一个状态的所有行为放在一个类中.这么一来我们将行为局部化了,并使得事情更容易改变和理解. 虫子还是拿订单系统来说事了 /// <summary> /// 状态接口 /// </summary> public interface SimpleState { //检查购物车 void CheckCart(); //检查账号 voi

hand first设计模式 -状态模式

状态模式:允许对象在内部状态改变时改变它的的行为.对象看起来好像修改了化的类. 将以超市购物为例--说明状态模式 所有状态抽象类 Java代码 public abstract class BuyStat { //在超市状态 public void inShop() { System.out.println("welcome come our shop,please start shoping"); } //选购商品状态 public void select() { System.out

.net设计模式实例之状态模式(State Pattern)

一.状态模式简介(Brief Introduction) 状态模式(State Pattern),当一个对象的内在状态改变时允许改变其行为,这个对象 看起来像是改变了其类. 二.解决的问题(What To Solve) 状态模式主要解决的是当控制一个对象状态装换的条件表达式过于复杂时的情况.把状态 的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简单化. 当一个对象行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可 以考虑使用状态模式了. 三.状态模式分析(Ana

【机房合作】状态模式与上机

在机房收费系统中,有几个业务逻辑是比较复杂的,比如说上机.下机.记得我在做第一版VB收费系统的时候,还特别地将上下机拿出来画了一个完整的流程图,要不这样做的话,最后的结果一定是懵了,也不想再继续写代码了. 在进行设计模式的学习之前,我们很有必要将上机这一业务逻辑完整的梳理一遍. 一.上机业务逻辑 1.判断卡号是否存在 2.判断卡号是否使用 3.判断卡号余额是否充足 4.判断卡号是否正在上机 5.执行上机,添加上机记录 这样一罗列,很明显,执行上机这一业务操作需要先经过四次判断.之前我们都是通过一

深入理解JavaScript系列(43):设计模式之状态模式详解_基础知识

介绍 状态模式(State)允许一个对象在其内部状态改变的时候改变它的行为,对象看起来似乎修改了它的类. 正文 举个例子,就比如我们平时在下载东西,通常就会有好几个状态,比如准备状态(ReadyState).下载状态(DownloadingState).暂停状态(DownloadPausedState).下载完毕状态(DownloadedState).失败状态(DownloadFailedState),也就是说在每个状态都只可以做当前状态才可以做的事情,而不能做其它状态能做的事儿. 由于Stat

策略模式的孪生兄弟——对状态模式的深度复习总结

俗话说,自己写的代码,6个月后也是别人的代码--复习!复习!复习!涉及的总结知识点如下: 和策略模式的比较 状态模式概念和例子 应用场景 责任链模式和状态模式对比 一种代码优化的思路 java.util.Iterator里也有状态模式的影子 状态模式的优缺点 有限状态机及其应用 前面有总结--策略模式,之前早就觉得策略和状态设计模式有一些相似-- 接口的常用用法都有什么?策略设计模式复习总结 我知道策略模式是对象的行为模式,其实就是对一系列级别平等的算法的封装,它不关心算法实现,让客户端去动态的