• 你程序会做饭嘛?我能!


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

    程序当然不能做饭。

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

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

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

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

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

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

    新建控制台项目:

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

    类库

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

    我们先来初始化餐厅。

    /**
     * 
     * @author 失足程序员
     * @Blog http://www.cnblogs.com/ty408/
     * @mail 492794628@qq.com
     * @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 492794628@qq.com
     * @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 492794628@qq.com
     * @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 492794628@qq.com
     * @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 492794628@qq.com
     * @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 492794628@qq.com
     * @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 492794628@qq.com
     * @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 492794628@qq.com
     * @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 492794628@qq.com
     * @phone 13882122019
     * 
     */
  • 相关阅读:
    实用图片滑块,传送带,幻灯片效果【附源码】
    Canvas 示例:4种超炫的网站动画背景效果
    GOCR.js – 使用 JS 识别出图片中的文本
    Flexslider
    30款最好的 Bootstrap 3.0 免费主题和模板
    应用 CSS3 动画实现12种风格的通知提示
    Sequence.js 实现带有视差滚动特效的图片滑块
    使用QFuture类监控异步计算的结果
    Qt中的常用容器类(解释比较全面,有插图)
    QMetaEnum获取枚举元信息
  • 原文地址:https://www.cnblogs.com/shizuchengxuyuan/p/4516851.html
Copyright © 2020-2023  润新知