【C#】枚举类型Enum与状态设计模式

来源:互联网 发布:ae 编程 编辑:程序博客网 时间:2024/06/02 04:59

一、枚举类型Enum的基本定义与使用

本来,C#的枚举类型没什么好说的,就是刚学编程的都会,甚至还会问,这废东西还不如写一大堆常量,拿回C++那套:

public const int A = 0;public const int B = 1;public const int C = 2;

不过确实,枚举类型就是由C++传统这套拿过来的。先不说它有什么好处,至少数组化、结构体化、类化之后,枚举可以使代码更易于维护,代码更清晰,有助于确保给变量指定合法的、期望的值。同时,你还需要如下代码:

using System;using System.Collections.Generic;using System.Text;namespace Enumerate{    enum ABC    {        A = 0,        B = 1,        C,    };    class Program    {        static void Main(string[] args)        {            Console.WriteLine((int)ABC.C);        }    }}

运行结果如下:


需要注意的是:

1、我不用再于ABC这个枚举类型enum中罗列C=2,C#会自动识别C=2的。

2、如果你要输出C=?,你必须将ABC.C转化成int。否则,如果你的代码写成这样,在输出ABC.C之前缺少一个强制类型转换的(int):

using System;using System.Collections.Generic;using System.Text;namespace Enumerate{    enum ABC    {        A = 0,        B = 1,        C,    };    class Program    {        static void Main(string[] args)        {            Console.WriteLine(ABC.C);        }    }}

你的输出是这样的:


二、枚举类型Enum在实际编程中的简单应用

当然,上述也只是一些小问题的小打小闹。并没有看出枚举类型Enum有什么卵用,但是如果你将这个枚举类型和《【C++】状态模式》(点击打开链接)这种设计模式联系起来,则大有用途。尤其在诸如Unity3D等需要一个死循环while支撑游戏编程中,也就是那些程序不关,循环不灭的程序中,状态设计模式的思想将被采用,枚举类型Enum同样也会大放异彩。

先写个简单的。

using System;using System.Collections.Generic;using System.Text;namespace Enumerate{    enum ABC    {        A = 0,        B = 1,        C,    };    class Program    {        static void Main(string[] args)        {            ABC abc = ABC.A;            while (true)            {                switch (abc)                {                    case ABC.A:                        Console.WriteLine("请输入B或者C进入状态B或者C,否则将处于状态A");                        string input = Console.ReadLine();                        if (input.Equals("B") || input.Equals("b"))                        {                            abc = ABC.B;                        }                        else if (input.Equals("C") || input.Equals("c"))                        {                            abc = ABC.C;                        }                        else                        {                            Console.WriteLine("还是处于状态A");                            abc = ABC.A;                        }                        break;                    case ABC.B:                        Console.WriteLine("来到状态B了,输出完成~回到状态A,继续期待你的光临");                        abc = ABC.A;                        break;                    case ABC.C:                        Console.WriteLine("来到状态C了,输出完成~回到状态A,继续期待你的光临");                        abc = ABC.A;                        break;                }            }        }    }}

运行结果如下:


此程序的平常状态为A,随时接受用户,或者说,随时等待着用户的输入,也就是在轮询。当用户输入特定的值,或者你可以深刻理解成:一旦遇到某种条件,程序将从平常状态A转换成状态B或者C处理别的事情,处理完成再转化成平常状态A。

举这个例子,我相信已经很好地模拟出一些游戏编程中永远在循环读取的update()函数,每一个游戏帧执行的update()类似就是类似于这里的while(true),而,如果你需要在update()函数中处理一些类似游戏主角、游戏对象或者游戏状态的东西,建议利用这种状态设计模式。

通过阅读上述代码,相信大家大致能看到枚举类型Enum与内含switch~case结构的死循环while(true)配合形成的设计模式。这里,枚举组,叫做ABC,那么你就可以利用ABC a=ABC.A,来定义一个类似指向这个枚举组的指针a,先指向枚举组ABC的A,然后a=ABC.某某,就指向其它状态了,可以随心所欲在状态中切换,就可以省去一大堆,连你自己都绕翻车的if~else if ~else渣结构了。

三、枚举类型Enum与状态设计模式

以上的代码,体现了一种状态设计模式的思想,当然,虽然这类代码更常见,但是,这并不是严格的状态设计模式。如果要写一个严格的状态设计模式,同样可以用到枚举类型Enum。还是用那道2011年下半年的软件设计师软考题目再来说明:

题目是这样的:

某大型商场内安装了多个简易的纸巾售卖机,自动出售2元钱一包的纸巾,且每次仅售出一包纸巾,纸巾售卖机的状态图如图5-1所示:



采用状态(State)模式来实现该纸巾售卖机,得到如图5-2所示的类图,其中类State为抽象类,定义了投币、退币、出纸巾等方法接口。类SoldOutState、NoQuarterState、HasQuarterState、SoldState分别对应图5-1纸巾售卖机的4种状态。售出纸巾、纸巾售卖、没有投币、有2元钱。

当然,这里我就不完全照抄软考题目中提供的伪代码格式了,自己用枚举类型Enum写完这个状态设计模式,满足题目的要求。

首先,你要注意到,这是一个纸巾售卖机,就算其处于待机状态,一旦有用户来用,你也要即时相应,也时刻就处于轮询状态,所以这是就考虑到先枚举几个状态,对于用户的动作,时刻做出切换,因此,代码如下,注意到void dispense();实质是TissueMachine自己的内部处理方法,不会给用户调用的。只是这里接口要求其继承者,对其所含有的方法的可访问xing

using System;namespace EnumStatePattern{    interface StateHandle    {        void insertQuarter();//“投币”按钮被按下        void ejectQuarter();//“退币”按钮被按下          void turnCrank();//“出纸巾”按钮被按下          void dispense();//正在售出纸巾           }    class TissueMachine : StateHandle    {        private enum State        {//自动售货机的四种可能状态            soldOutState = -1,//纸巾卖完            noQuarterState = 0,//没有投币            hasQuarterState = 1,//已有投币            soldState = 2,//正在售出        }        private int money;//自动售货机当前拥有的投币数量        private State state;//自动售货机当前的状态        public TissueMachine()        {//自动售货机的初始化            this.money = 0;            this.state = State.noQuarterState;        }        public void insertQuarter()        {            switch (this.state)            {                case State.soldOutState:                    Console.WriteLine("纸巾已经卖完了,本纸巾自动售货机停机!");                    break;                case State.noQuarterState:                    this.money += 2;                    Console.WriteLine("感谢投币!当前纸巾机存有币:{0}", this.money);                    this.state = State.hasQuarterState;                    break;                case State.hasQuarterState:                    this.money += 2;                    Console.WriteLine("感谢投币!当前纸巾机存有币:{0}", this.money);                    break;                case State.soldState:                    Console.WriteLine("正在售出!请不要进行操作。");                    break;            }        }        public void ejectQuarter()        {            switch (this.state)            {                case State.soldOutState:                    Console.WriteLine("纸巾已经卖完了,本纸巾自动售货机停机!");                    break;                case State.noQuarterState:                    Console.WriteLine("投币机没有投币,无法退币!");                    break;                case State.hasQuarterState:                    this.money -= 2;                    Console.WriteLine("你的投币已经退回!当前纸巾机存有币:{0}", this.money);                    if (this.money == 0)                    {                        this.state = State.noQuarterState;                    }                    break;                case State.soldState:                    Console.WriteLine("正在售出!请不要进行操作。");                    break;            }        }        public void turnCrank()        {            switch (this.state)            {                case State.soldOutState:                    Console.WriteLine("纸巾已经卖完了,本纸巾自动售货机停机!");                    break;                case State.noQuarterState:                    Console.WriteLine("请投币!");                    break;                case State.hasQuarterState:                    this.state = State.soldState;                    Console.WriteLine("开始售出纸巾");                    dispense();                    break;                case State.soldState:                    Console.WriteLine("正在售出!请不要进行操作。");                    break;            }        }        public void dispense()        {            this.money -= 2;            Console.WriteLine("你的纸巾,请拿好!当前纸巾机存有币:{0}", this.money);            if (this.money == 0)            {                this.state = State.noQuarterState;            }            else            {                this.state = State.hasQuarterState;            }        }    }    class Program    {        static void Main(string[] args)        {            Console.WriteLine("输入1投币,输入2退币,输入3售出纸巾");            TissueMachine tissueMachine = new TissueMachine();            while (true)            {                switch (int.Parse(Console.ReadLine()))                {                    case 1:                        tissueMachine.insertQuarter();                        break;                    case 2:                        tissueMachine.ejectQuarter();                        break;                    case 3:                        tissueMachine.turnCrank();                        break;                }            }        }    }}

运行结果如下图所示:


大家可以注意到,上述代码的主函数非常非常简单,非常简单的同时,也非常清晰,用户输入什么则执行什么方法。

    class Program    {        static void Main(string[] args)        {            Console.WriteLine("输入1投币,输入2退币,输入3售出纸巾");            TissueMachine tissueMachine = new TissueMachine();            while (true)            {                switch (int.Parse(Console.ReadLine()))                {                    case 1:                        tissueMachine.insertQuarter();                        break;                    case 2:                        tissueMachine.ejectQuarter();                        break;                    case 3:                        tissueMachine.turnCrank();                        break;                }            }        }    }

而在TissueMachine这个类当中,一开始就使用了枚举类型Enum清晰罗列了4种基本状态。

private enum State{//自动售货机的四种可能状态soldOutState = -1,//纸巾卖完noQuarterState = 0,//没有投币hasQuarterState = 1,//已有投币soldState = 2,//正在售出}

在TissueMachine接下来的各个方法中,皆使用switch~case结构,针对TissueMachine处于不同的状态而作出不同相应。用户执行某些方法,在某特定的状态的话,会发生状态转换,从而保证这个方法的顺利执行。

这样的代码写作,由于利用枚举类型Enum与状态设计模式,使得程序猿写得清晰的同时,其它维护的程序猿也清晰。彻底可以忘掉,都能把自己绕死的if~else if~else结构,吃力还不讨好。

针对TissueMachine永远在轮询用户输入的类,它注定要处于无限循环之中,所以我们要以状态划分其处理方法。此时枚举类型Enum就派上用场了。