zoukankan      html  css  js  c++  java
  • 【状态模式】 State Pattern

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

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

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

     

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

     

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

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

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

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

     

    直接上代码(可能和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; }
            }
        }
    View Code

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

     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;
            }
        }
    View Code

    饮料的存储库

     public class SoftDrinkRepository
        {
    
          
            static SoftDrinkRepository()
            {
                SoftDrinks = new List<SoftDrink>();
                AddSoftDrink(new SoftDrink { Name = "可乐", Count = 5, Price = 3 });
                AddSoftDrink(new SoftDrink { Name = "果粒橙", Count = 1, Price = 3 });
                AddSoftDrink(new SoftDrink { Name = "咖啡", Count = 5, Price = 3 });
            }
    
            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);
            }
        }
    View Code

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

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

    接口:

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

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

    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("已经售完");
            }
        }
    View Code

    上下文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;
            }
        }
    View Code

    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 = 0;
                });
    
            }
    
            private void btnInputMoney_Click(object sender, EventArgs e)
            {
                var money = 0;
                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(0, 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);
                }
            }
    View Code

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

    后记: 

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

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

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

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

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

  • 相关阅读:
    三个心态做人做学问 沧海
    成功走职场要找准自己的"快捷键" 沧海
    免费离线下载 拂晓风起
    Hibernate 获取某个表全部记录时 奇怪现象 (重复出现某个记录) 拂晓风起
    无法读取mdb 如果连接不了ACCESS mdb文件,就尝试安装MDAC 拂晓风起
    Netbeans 使用 Hibernate 逆向工程 生成hbm和pojo 拂晓风起
    如何点击单选框 radio 后面的文字,选中单选框 拂晓风起
    Java 连接access 使用access文件 不用配置 拂晓风起
    mysql下如何执行sql脚本 拂晓风起
    Hibernate配置access Hibernate 连接 access 拂晓风起
  • 原文地址:https://www.cnblogs.com/guochenkai/p/3977787.html
Copyright © 2011-2022 走看看