別嘲笑這個標題。我想了很久。有點“投機取巧”的功效吧!
程序當然不能做飯。
之前的我們的系列文章,介紹, 多線程執行,任務派發。定時器執行。腳本加載。程序狀態機。
這些都是零零散散,或者說都是模塊化介紹,以及模塊測試用例。
那麼今天我們就來模擬正常程序流程。使用上述的功能性代碼完成流程。
當然今天的測試用例程序肯定和做飯有關。今天要做的是模擬一個餐廳的流程。
完成 客人入座 -> 點菜 -> 等待就餐 -> 就餐 -> 等待結賬 -> 結賬 -> 離開.
期間包括 等待就餐 添加茶水,就餐的添加茶水,添加米飯等隨機事件
新建控制台項目:
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 * */