当前位置: 代码迷 >> C# >> 你程序会做饭嘛?小弟我能
  详细解决方案

你程序会做饭嘛?小弟我能

热度:70   发布时间:2016-05-05 03:44:36.0
你程序会做饭嘛?我能!

别嘲笑这个标题。我想了很久。有点“投机取巧”的功效吧!

程序当然不能做饭。

之前的我们的系列文章,介绍, 多线程执行,任务派发。定时器执行。脚本加载。程序状态机。

这些都是零零散散,或者说都是模块化介绍,以及模块测试用例。

那么今天我们就来模拟正常程序流程。使用上述的功能性代码完成流程。

当然今天的测试用例程序肯定和做饭有关。今天要做的是模拟一个餐厅的流程。

完成 客人入座 -> 点菜 -> 等待就餐 -> 就餐 -> 等待结账 -> 结账 -> 离开.

期间包括 等待就餐 添加茶水,就餐的添加茶水,添加米饭等随机事件

新建控制台项目:

Sz.Network.DiningRoom 用于存放主文件项目

类库

Sz.Network.DiningRoom.Scripts  用于存放脚本文件项目

 

我们先来初始化餐厅。

/** *  * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 *  */namespace Sz.Network.DiningRoom{    /// <summary>    ///     /// </summary>    public class 餐厅    {        private static 餐厅 instance = new 餐厅();        public static 餐厅 GetInstance { get { return instance; } }        public long 全局线程 = 0;        public long 厨师s = 0;        public long 传菜员s = 0;        public long 服务员s = 0;        public long 配菜员s = 0;        public long 收银员s = 0;        public long 洗菜员s = 0;        public 客人[] table = null;        public void Init(int tableSize)        {            Logger.Info("初始化餐厅");            //所有的工作人员都是一个线程            全局线程 = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("全局线程", 1));            //所有的工作人员都是一个线程            厨师s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("厨师", 3));            //所有的工作人员都是一个线程            传菜员s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("传菜员", 5));            //所有的工作人员都是一个线程            服务员s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("服务员", 5));            //所有的工作人员都是一个线程            配菜员s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("配菜员", 3));            //所有的工作人员都是一个线程            收银员s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("收银员", 1));            //所有的工作人员都是一个线程            洗菜员s = ThreadPool.ThreadManager.GetInstance.GetThreadModel(new ThreadPool.ThreadModel("洗菜员", 2));            table = new 客人[tableSize];            for (int i = 0; i < tableSize; i++)            {                Logger.Info("初始化餐桌 " + (i + 1) + " 号桌");            }        }    }}

每一个工作人员都是一个线程。模拟线程。

我们这里,餐厅配置:"厨师", 3 "传菜员", 5  "服务员", 5  "配菜员", 3  "收银员", 1  "洗菜员", 2

各个环节的人员都不相同,且每一步操作都不进相同。

接下来我们初始化客人,

/** *  * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 *  */namespace Sz.Network.DiningRoom{    public class 客人    {        public static EnumStatus Status入座 = new EnumStatus(1 << 0, 0x000000);        public static EnumStatus Status取消 = new EnumStatus(1 << 1, 0x000000);        public static EnumStatus Status点菜 = new EnumStatus(1 << 2, 0x000000);        public static EnumStatus Status就餐 = new EnumStatus(1 << 3, 0x000000);        public static EnumStatus Status结账中 = new EnumStatus(1 << 4, 0x000000);        public static EnumStatus Status等待就餐 = new EnumStatus(1 << 5, 0x000000);        public static EnumStatus Status等待结账 = new EnumStatus(1 << 6, 0x000000);        /// <summary>        /// 存储临时数据的        /// </summary>        public ObjectAttribute TempAttribute = new ObjectAttribute();        /// <summary>        /// 客人当前的状态        /// </summary>        public EnumStatus Staus = new EnumStatus(0, 0x000000);        public List<菜肴> 菜肴s = new List<菜肴>();        public int TableID { get; set; }        /// <summary>        /// 每一个客人的随机标识        /// </summary>        public string guidID { get; set; }        public 客人(int tableID)        {            guidID = Guid.NewGuid().ToString().Replace("-", "");            this.TableID = tableID;            Staus |= Status入座;            Show();        }        public void 点菜()        {            ThreadPool.ThreadManager.GetInstance.AddTask(餐厅.GetInstance.服务员s, new Task点菜(this));            Task随机事件发生处理器 task = new Task随机事件发生处理器(this.TableID + " 号桌客人 上碗筷");            ThreadPool.ThreadManager.GetInstance.AddTask(餐厅.GetInstance.服务员s, task);        }        public void Add点菜(菜肴 菜)        {            菜肴s.Add(菜);            ThreadPool.ThreadManager.GetInstance.AddTask(餐厅.GetInstance.洗菜员s, new Task菜(this, 菜));        }        public void Show()        {            string 状态 = "";            if (Staus.HasFlag(Status入座))            {                状态 = "入座";            }            else if (Staus.HasFlag(Status取消))            {                状态 = "取消";            }            else if (Staus.HasFlag(Status点菜))            {                状态 = "点菜";            }            else if (Staus.HasFlag(Status等待就餐))            {                状态 = "等待就餐";            }            else if (Staus.HasFlag(Status就餐))            {                状态 = "就餐";            }            else if (Staus.HasFlag(Status等待结账))            {                状态 = "等待结账";            }            else if (Staus.HasFlag(Status结账中))            {                状态 = "结账中";            }            Logger.Info(this.TableID + " 号桌子 客人 " + this.guidID + " 当前状态:" + 状态);        }    }}

 

初始化菜肴

/** *  * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 *  */namespace Sz.Network.DiningRoom{    public class 菜肴    {        public static EnumStatus Status点菜 = new EnumStatus(1 << 0, 0x000000);        public static EnumStatus Status取消 = new EnumStatus(1 << 1, 0x000000);        public static EnumStatus Status洗菜 = new EnumStatus(1 << 2, 0x000000);        public static EnumStatus Status配菜 = new EnumStatus(1 << 3, 0x000000);        public static EnumStatus Status炒菜 = new EnumStatus(1 << 4, 0x000000);        public static EnumStatus Status传菜 = new EnumStatus(1 << 5, 0x000000);        public static EnumStatus Status就餐 = new EnumStatus(1 << 6, 0x000000);        public static EnumStatus Status结束就餐 = new EnumStatus(1 << 7, 0x000000);        public string Name { get; private set; }        public EnumStatus Staus = new EnumStatus(0, 0x000000);        /// <summary>        /// 存储临时数据的        /// </summary>        public ObjectAttribute TempAttribute = new ObjectAttribute();        public 菜肴(string name)        {            this.Name = name;            Staus |= Status点菜;            Show();        }        public void Show()        {            string 状态 = "";            if (Staus.HasFlag(Status点菜))            {                状态 = "点菜";            }            else if (Staus.HasFlag(Status取消))            {                状态 = "取消";            }            else if (Staus.HasFlag(Status洗菜))            {                状态 = "洗菜";            }            else if (Staus.HasFlag(Status配菜))            {                状态 = "配菜";            }            else if (Staus.HasFlag(Status炒菜))            {                状态 = "炒菜";            }            else if (Staus.HasFlag(Status传菜))            {                状态 = "传菜";            }            else if (Staus.HasFlag(Status就餐))            {                状态 = "就餐";            }            Logger.Info(this.Name + " 当前状态:" + 状态);        }    }}

我们需要创建一个定时器任务,对餐桌和客人进行状态监测和随机事件发生器

/** *  * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 *  */namespace Sz.Network.DiningRoom{    public class TimerTask : ThreadPool.TimerTask    {        /// <summary>        /// 间隔 5000 毫秒执行一次        /// </summary>        public TimerTask()            : base(餐厅.GetInstance.全局线程, 2000)        {        }        public override void Run()        {                       IEnumerable<IScript餐桌检查器> checkScripts = LoadScriptPool.LoadScriptManager.GetInstance.GetInstances<IScript餐桌检查器>();            foreach (var item in checkScripts)            {                item.Run();            }        }    }}

由于我们餐桌检查器是一个不定数,所以需要放到脚本去。方便更新程序代码。

在脚本项目里面创建脚本文件

/** *  * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 *  */namespace Sz.Network.DiningRoom.Scripts{    public class Script餐桌检查器 : IScript餐桌检查器    {        Random random = new Random(DateTime.Now.Millisecond);        public Script餐桌检查器()        {        }        public void Run()        {            Logger.Info("==================================Script餐桌检查器=======================================");            for (int i = 0; i < 餐厅.GetInstance.table.Length; i++)            {                if (餐厅.GetInstance.table[i] == null)                {                    int randomValue = random.Next(10000);                    if (randomValue < 5000)                    {                        客人 客 = new 客人(i + 1);                        餐厅.GetInstance.table[i] = 客;                    }                }                else                {                    客人 客 = 餐厅.GetInstance.table[i];                    if (客.Staus.HasFlag(客人.Status入座))                    {                        ///如果客人刚刚入座,执行点菜,移交给服务员                        客.Staus |= 客人.Status点菜;                        客.点菜();                    }                    else if (客.Staus.HasFlag(客人.Status等待就餐))                    {                        bool isFor = true;                        foreach (var item in 客.菜肴s)                        {                            if (!item.Staus.HasFlag(菜肴.Status就餐))                            {                                isFor = false;                                break;                            }                        }                        if (isFor)                        {                            客.Staus |= 客人.Status就餐;                            //模拟客人吃饭需要30到50秒                            客.TempAttribute["Status就餐"] = SzExtensions.CurrentTimeMillis() + (random.Next(3, 6)) * 10 * 1000;                        }                        else                        {                            //模拟随机事件                            int randomValue = random.Next(10000);                            if (randomValue < 6000)                            {                                Logger.Info("随机事件发生 " + (i + 1) + " 号桌客人 添加茶水");                                Task随机事件发生处理器 task = new Task随机事件发生处理器((i + 1) + " 号桌客人 添加茶水");                                ThreadPool.ThreadManager.GetInstance.AddTask(餐厅.GetInstance.服务员s, task);                            }                        }                    }                    else if (客.Staus.HasFlag(客人.Status就餐))                    {                        if (客.TempAttribute.GetlongValue("Status就餐") < SzExtensions.CurrentTimeMillis())                        {                            客.Staus |= 客人.Status等待结账;                        }                        else                        {                            //模拟随机事件                            string msg = "";                            int randomValue = random.Next(10000);                            if (randomValue < 3000)                            {                                msg = " 添加米饭";                            }                            else if (randomValue < 6000)                            {                                msg = " 添加茶水";                            }                            if (!string.IsNullOrWhiteSpace(msg))                            {                                Logger.Info("随机事件发生 " + (i + 1) + " 号桌客人 " + msg);                                Task随机事件发生处理器 task = new Task随机事件发生处理器((i + 1) + " 号桌客人 " + msg);                                ThreadPool.ThreadManager.GetInstance.AddTask(餐厅.GetInstance.服务员s, task);                            }                        }                    }                    else if (客.Staus.HasFlag(客人.Status等待结账))                    {                        客.Staus |= 客人.Status结账中;                    }                    else if (客.Staus.HasFlag(客人.Status结账中))                    {                        Logger.Info((i + 1) + " 号桌客人 结束就餐 送走客人");                        餐厅.GetInstance.table[i] = null;                        return;                    }                    客.Show();                }            }        }    }}

点菜也同样为方便程序更新,代码放在脚本执行

/** *  * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 *  */namespace Sz.Network.DiningRoom.Scripts{    public class Script点菜 : IScript点菜    {        public Script点菜()        {        }        public void Run(客人 客)        {            List<string> 菜肴_荤菜s = new List<string>() { "回锅肉", "青椒肉丝", "东坡肘子", "糖醋排骨", "鱼香肉丝" };            List<string> 菜肴_素菜s = new List<string>() { "空心菜", "凤尾", "素炒竹笋", "白油丝瓜" };            List<string> 菜肴_汤s = new List<string>() { "番茄煎蛋汤", "紫菜蛋花汤", "酸菜粉丝汤", "素菜汤", "肉片汤" };            Random random = new Random(DateTime.Now.Millisecond);            {                //int 数量 = random.Next(1, 菜肴_荤菜s.Count);                int 数量 = 1;                for (int i = 0; i < 数量; i++)                {                    int index = random.Next(菜肴_荤菜s.Count);                    string name = 菜肴_荤菜s[index];                    菜肴_荤菜s.RemoveAt(index);                    菜肴 菜 = new 菜肴(name);                    客.Add点菜(菜);                }            }            {                //int 数量 = random.Next(1, 菜肴_素菜s.Count);                int 数量 = 1;                for (int i = 0; i < 数量; i++)                {                    int index = random.Next(菜肴_素菜s.Count);                    string name = 菜肴_素菜s[index];                    菜肴_素菜s.RemoveAt(index);                    菜肴 菜 = new 菜肴(name);                    客.Add点菜(菜);                }            }            {                //int 数量 = random.Next(1, 菜肴_汤s.Count);                int 数量 = 1;                for (int i = 0; i < 数量; i++)                {                    int index = random.Next(菜肴_汤s.Count);                    string name = 菜肴_汤s[index];                    菜肴_汤s.RemoveAt(index);                    菜肴 菜 = new 菜肴(name);                    客.Add点菜(菜);                }            }            客.Staus |= 客人.Status等待就餐;                    }    }}

接下来,就是菜的流程任务执行器

/** *  * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 *  */namespace Sz.Network.DiningRoom{    public class Task菜 : ThreadPool.TaskModel    {        public 客人 客 { get; set; }        public 菜肴 _菜肴 { get; set; }        public Task菜(客人 客, 菜肴 _菜肴)        {            this.客 = 客;            this._菜肴 = _菜肴;        }        public override void Run()        {            Random random = new Random(DateTime.Now.Millisecond);            string 事件 = "";            EnumStatus tempStatus = null;            long threadID = 0;            if (_菜肴.Staus.HasFlag(菜肴.Status点菜))            {                事件 = "洗菜";                tempStatus = 菜肴.Status洗菜;                threadID = 餐厅.GetInstance.洗菜员s;            }            else if (_菜肴.Staus.HasFlag(菜肴.Status取消))            {                事件 = "取消";                tempStatus = 菜肴.Status取消;            }            else if (_菜肴.Staus.HasFlag(菜肴.Status洗菜))            {                事件 = "配菜";                tempStatus = 菜肴.Status配菜;                threadID = 餐厅.GetInstance.配菜员s;            }            else if (_菜肴.Staus.HasFlag(菜肴.Status配菜))            {                事件 = "炒菜";                tempStatus = 菜肴.Status炒菜;                threadID = 餐厅.GetInstance.厨师s;            }            else if (_菜肴.Staus.HasFlag(菜肴.Status炒菜))            {                事件 = "传菜";                tempStatus = 菜肴.Status传菜;                threadID = 餐厅.GetInstance.传菜员s;            }            else            {                return;            }            int timer = random.Next(2000, 5000);            ///模拟耗时            Thread.Sleep(timer);            ///修改菜肴的状态            this._菜肴.Staus |= tempStatus;            Logger.Info(Thread.CurrentThread.Name + "  " + 客.TableID + " 号桌 客人 " + this._菜肴.Name +" "+ 事件 + " 耗时:" + timer);            if (this._菜肴.Staus.HasFlag(菜肴.Status传菜))            {                ///修改菜肴的状态                this._菜肴.Staus |= 菜肴.Status就餐;            }            if (threadID > 0)            {                //移交到下一个工作人员(线程)                ThreadPool.ThreadManager.GetInstance.AddTask(threadID, this);            }        }    }}

我们修改一下餐厅的 init 方法

 //加载脚本            LoadScriptPool.LoadScriptManager.GetInstance.LoadCSharpFile(new string[] { @"..\..\..\Sz.Network.DiningRoom.Scripts\" });            //初始化定时器任务            ThreadPool.ThreadManager.GetInstance.AddTimerTask(new TimerTask());

 

菜肴的流程,交给了 Task菜 类处理,菜肴的状态值修改也是要交给 Task菜 修改的,保证了在同一线程修改状态值就保证状态值的正常。

既然说了要有随机事件发生,那肯定少不了随机事件的处理器

/** *  * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 *  */namespace Sz.Network.DiningRoom{    public class Task随机事件发生处理器 : ThreadPool.TaskModel    {        string msg;        public Task随机事件发生处理器(string msg)        {            this.msg = msg;        }        public override void Run()        {            Random random = new Random(DateTime.Now.Millisecond);            int timer = random.Next(2000, 5000);            //模拟随机事件耗时            Thread.Sleep(timer);            Logger.Info(Thread.CurrentThread.Name + " 处理随机事件发生 " + msg + " 耗时:" + timer);        }    }}

 

这样我们就能启动程序了测试一下了。

 

整个流程就是,客人入座,点菜,,被分配到到洗菜,配菜,炒菜,传菜。就餐。结账。等一系列流程。

由于人员配置不同,具体工作耗时不同,所以一切都发生都是不定项;

每一个操作在移交给下一个工作者(线程)都是不定操作。而每一个工作者(线程)都有先来后到的原则进行自己工作的处理;

 

我们未来方便测试和看清楚执行流程。我们只开启一个餐桌;

 餐厅.GetInstance.Init(1);

 

我的程序真的能做饭哦~!

 

不知道,这样讲,是否能帮你讲明白呢???

老规矩,全套源码奉献 svn 地址    http://code.taobao.org/svn/flynetwork_csharp/trunk/Flynetwork/BlogTest

跪求保留

/** *  * @author 失足程序员 * @Blog http://www.cnblogs.com/ty408/ * @mail [email protected] * @phone 13882122019 *  */

 

5楼cposture
说实话,一大堆吓人的代码,找不出逻辑,不知从哪看起,而且不知是什么语言,文章说的是脚本语言
Re: 失足程序员
@cposture,引用说实话,一大堆吓人的代码,找不出逻辑,不知从哪看起,而且不知是什么语言,文章说的是脚本语言,看来你没有看过我之前的文章,所谓脚本只是把C#的代码作为脚本执行而已。是为了程序的方便更新问题。也就是热更新程序。
4楼Little Ming
代码逻辑看的不是很懂, 不过想吐槽一下中文命名问题.
Re: 失足程序员
@Little Ming,引用代码逻辑看的不是很懂, 不过想吐槽一下中文命名问题.,中文命名的问题是在这个测试用例里面为了很清晰明了。,并且中文为什么要遭到歧视?
3楼流光_
哈哈,前排占座,逻辑理的很清楚
2楼cposture
支持一下,虽然不是很懂
Re: 失足程序员
@cposture,引用支持一下,虽然不是很懂,不知道是哪里不懂???或者你看过之前的文章嘛?这里有些基础的东西是在之前的文章讲解的。
1楼zhoumy
离模块化还远呢。比如再加个状态,客人结账后,发现找零不对,又返回重新计算找零。加个状态你怎么处理?改已有代码?
Re: 失足程序员
@zhoumy,引用离模块化还远呢。比如再加个状态,客人结账后,发现找零不对,又返回重新计算找零。加个状态你怎么处理?改已有代码?,至于你说的离模块化还远,跪求指教。,至于说发现找零不对,这考虑的就多了,比如,人走了,又或者人没走。,并且还存在,客人点了菜,不要了,客人点了菜,突然走了,客人正在吃饭的时候有点了菜。这些都是问题!!!!
  相关解决方案