附加题1:关于INTERFACE的改进方式。基于对现实的考虑。可以将电梯分为几个区域。在IElevator, IPassenger,IRequest中添加电梯区域代码,区域代码需求。更贴近实际。并且在设计scheduler时考虑不同区域不同电梯的行动模式,在通知需求时也需按照需求区域分别通知相应区域的电梯。让学生考虑的层面更多,有利于编写更有逻辑性的代码。
附加题2:我们设计了一个简单的UI界面。用户输入电梯参数与乘客参数的地址。程序会按时间顺序显示电梯的当前层数以及当前运行状态:上升、下降、停止。
源代码一共包含三个新代码文件。
Form1:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using World; using Scheduler; using Elevator; using commons; namespace UI { public partial class Form1 : Form { public World.Program wp; string elev; string passenger; public Form1() { wp = new World.Program(); InitializeComponent(); } public void elev_Update(object sender, EventArgs e) { Elevator.SenElevator ele = (Elevator.SenElevator)sender; Label ThisElev; ThisElev = elev1; if (ele.ID == 1) ThisElev = elev2; if (ele.ID == 2) ThisElev = elev3; if (ele.ID == 3) ThisElev = elev4; //Point loca = ThisElev.Location; //Console.WriteLine("Update--->{0} req {1}", ele.ID, loca.Y); //ThisElev.Location = loca; // if (!ThisElev.InvokeRequired) //{ Control.CheckForIllegalCrossThreadCalls = false; if (ele.CurrentStatus.CurrentDirection == Direction.Up) ThisElev.Text = ele.CurrentStatus.CurrentFloor.ToString() +" 上升"; if (ele.CurrentStatus.CurrentDirection == Direction.Down) ThisElev.Text = ele.CurrentStatus.CurrentFloor.ToString() +" 下降"; if (ele.CurrentStatus.CurrentDirection == Direction.No) ThisElev.Text = ele.CurrentStatus.CurrentFloor.ToString() +" 停止"; //} } private void Form1_Load(object sender, EventArgs e) { } private void label1_Click(object sender, EventArgs e) { } private void label3_Click(object sender, EventArgs e) { } private void label5_Click(object sender, EventArgs e) { } private void textBox1_TextChanged(object sender, EventArgs e) { elev = textBox1.Text; } private void button1_Click(object sender, EventArgs e) { // elev = "F:\pair\2013PairProject2\list\elevators.xml"; //passenger = "F:\pair\2013PairProject2\list\passenger1.xml"; wp.WorldInit(elev, passenger); } private void textBox2_TextChanged(object sender, EventArgs e) { passenger = textBox2.Text; } private void textBox3_TextChanged(object sender, EventArgs e) { } private void textBox4_TextChanged(object sender, EventArgs e) { } private void textBox5_TextChanged(object sender, EventArgs e) { } private void textBox6_TextChanged(object sender, EventArgs e) { } private void label8_Click(object sender, EventArgs e) { } private void label2_Click(object sender, EventArgs e) { } private void label6_Click(object sender, EventArgs e) { } private void label9_Click(object sender, EventArgs e) { } private void label10_Click(object sender, EventArgs e) { } private void label8_Click_1(object sender, EventArgs e) { } } }
FormDesigner:
namespace UI { partial class Form1 { /// <summary> /// 必需的设计器变量。 /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 清理所有正在使用的资源。 /// </summary> /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows 窗体设计器生成的代码 /// <summary> /// 设计器支持所需的方法 - 不要 /// 使用代码编辑器修改此方法的内容。 /// </summary> private void InitializeComponent() { this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.label3 = new System.Windows.Forms.Label(); this.label4 = new System.Windows.Forms.Label(); this.label5 = new System.Windows.Forms.Label(); this.label6 = new System.Windows.Forms.Label(); this.label7 = new System.Windows.Forms.Label(); this.button1 = new System.Windows.Forms.Button(); this.textBox1 = new System.Windows.Forms.TextBox(); this.textBox2 = new System.Windows.Forms.TextBox(); this.elev1 = new System.Windows.Forms.Label(); this.elev2 = new System.Windows.Forms.Label(); this.elev3 = new System.Windows.Forms.Label(); this.elev4 = new System.Windows.Forms.Label(); this.SuspendLayout(); // // label1 // this.label1.AutoSize = true; this.label1.Font = new System.Drawing.Font("楷体", 30F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label1.Location = new System.Drawing.Point(195, 21); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(177, 40); this.label1.TabIndex = 0; this.label1.Text = "电梯调度"; this.label1.Click += new System.EventHandler(this.label1_Click); // // label2 // this.label2.AutoSize = true; this.label2.Font = new System.Drawing.Font("隶书", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label2.Location = new System.Drawing.Point(47, 89); this.label2.Name = "label2"; this.label2.Size = new System.Drawing.Size(179, 19); this.label2.TabIndex = 1; this.label2.Text = "电梯参数文件路径:"; this.label2.Click += new System.EventHandler(this.label2_Click); // // label3 // this.label3.AutoSize = true; this.label3.Font = new System.Drawing.Font("隶书", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label3.Location = new System.Drawing.Point(46, 140); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(179, 19); this.label3.TabIndex = 2; this.label3.Text = "乘客参数文件路径:"; this.label3.Click += new System.EventHandler(this.label3_Click); // // label4 // this.label4.AutoSize = true; this.label4.Font = new System.Drawing.Font("隶书", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label4.Location = new System.Drawing.Point(47, 195); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(152, 16); this.label4.TabIndex = 3; this.label4.Text = "电梯0当前运动状态:"; // // label5 // this.label5.AutoSize = true; this.label5.Font = new System.Drawing.Font("隶书", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label5.Location = new System.Drawing.Point(48, 240); this.label5.Name = "label5"; this.label5.Size = new System.Drawing.Size(152, 16); this.label5.TabIndex = 4; this.label5.Text = "电梯1当前运动状态:"; this.label5.Click += new System.EventHandler(this.label5_Click); // // label6 // this.label6.AutoSize = true; this.label6.Font = new System.Drawing.Font("隶书", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label6.Location = new System.Drawing.Point(47, 290); this.label6.Name = "label6"; this.label6.Size = new System.Drawing.Size(152, 16); this.label6.TabIndex = 5; this.label6.Text = "电梯2当前运动状态:"; this.label6.Click += new System.EventHandler(this.label6_Click); // // label7 // this.label7.AutoSize = true; this.label7.Font = new System.Drawing.Font("隶书", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.label7.Location = new System.Drawing.Point(47, 339); this.label7.Name = "label7"; this.label7.Size = new System.Drawing.Size(152, 16); this.label7.TabIndex = 6; this.label7.Text = "电梯3当前运动状态:"; // // button1 // this.button1.Font = new System.Drawing.Font("隶书", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.button1.Location = new System.Drawing.Point(227, 384); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(124, 39); this.button1.TabIndex = 7; this.button1.Text = "运 行"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.button1_Click); // // textBox1 // this.textBox1.Location = new System.Drawing.Point(265, 89); this.textBox1.Name = "textBox1"; this.textBox1.Size = new System.Drawing.Size(212, 21); this.textBox1.TabIndex = 8; this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged); // // textBox2 // this.textBox2.Location = new System.Drawing.Point(265, 138); this.textBox2.Name = "textBox2"; this.textBox2.Size = new System.Drawing.Size(212, 21); this.textBox2.TabIndex = 9; this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged); // // elev1 // this.elev1.AutoSize = true; this.elev1.Location = new System.Drawing.Point(275, 195); this.elev1.Name = "elev1"; this.elev1.Size = new System.Drawing.Size(29, 12); this.elev1.TabIndex = 14; this.elev1.Text = "停止"; this.elev1.Click += new System.EventHandler(this.label8_Click); // // elev2 // this.elev2.AutoSize = true; this.elev2.Location = new System.Drawing.Point(275, 244); this.elev2.Name = "elev2"; this.elev2.Size = new System.Drawing.Size(29, 12); this.elev2.TabIndex = 15; this.elev2.Text = "停止"; this.elev2.Click += new System.EventHandler(this.label8_Click_1); // // elev3 // this.elev3.AutoSize = true; this.elev3.Location = new System.Drawing.Point(277, 290); this.elev3.Name = "elev3"; this.elev3.Size = new System.Drawing.Size(29, 12); this.elev3.TabIndex = 16; this.elev3.Text = "停止"; this.elev3.Click += new System.EventHandler(this.label9_Click); // // elev4 // this.elev4.AutoSize = true; this.elev4.Location = new System.Drawing.Point(279, 342); this.elev4.Name = "elev4"; this.elev4.Size = new System.Drawing.Size(29, 12); this.elev4.TabIndex = 17; this.elev4.Text = "停止"; this.elev4.Click += new System.EventHandler(this.label10_Click); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(589, 463); this.Controls.Add(this.elev4); this.Controls.Add(this.elev3); this.Controls.Add(this.elev2); this.Controls.Add(this.elev1); this.Controls.Add(this.textBox2); this.Controls.Add(this.textBox1); this.Controls.Add(this.button1); this.Controls.Add(this.label7); this.Controls.Add(this.label6); this.Controls.Add(this.label5); this.Controls.Add(this.label4); this.Controls.Add(this.label3); this.Controls.Add(this.label2); this.Controls.Add(this.label1); this.Font = new System.Drawing.Font("隶书", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.Name = "Form1"; this.Text = "Form1"; this.Load += new System.EventHandler(this.Form1_Load); this.ResumeLayout(false); this.PerformLayout(); } #endregion public System.Windows.Forms.Label label1; public System.Windows.Forms.Label label2; public System.Windows.Forms.Label label3; public System.Windows.Forms.Label label4; public System.Windows.Forms.Label label5; public System.Windows.Forms.Label label6; public System.Windows.Forms.Label label7; public System.Windows.Forms.Button button1; public System.Windows.Forms.TextBox textBox1; public System.Windows.Forms.TextBox textBox2; public System.Windows.Forms.Label elev1; public System.Windows.Forms.Label elev2; public System.Windows.Forms.Label elev3; public System.Windows.Forms.Label elev4; } }
Program:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; using World; using commons; namespace UI { static class Program { /// <summary> /// 应用程序的主入口点。 /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Form1 form = new Form1(); form.wp.ElevUpdate += new World.Program.ElevUpdateHandler(form.elev_Update); Application.Run(form); } } }
另外在源代码中的主函数也有相应改动:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using commons; using Elevator; using Passenger; using Scheduler; using System.Threading; using Loader; namespace World { public class Program { static List<SenElevator> AllElevators; static List<SigmaPassenger> AllPassengers; //sorted by DirectionReqTime static IScheduler NaiveScheduler; public Thread TickGoes; PassengerLoader _passengerLoader; ElevatorLoader _elevatorLoader; int ticks = 0; public delegate void ElevUpdateHandler(object sender, EventArgs e); public event ElevUpdateHandler ElevUpdate; bool AreElevatorsIdle() { bool ret = true; foreach (SenElevator e in AllElevators) ret = ret && e.IsIdle; return ret; } public void WorldInit(string xmlElv, string xmlPassengers) { _passengerLoader = new PassengerLoader(xmlPassengers); _elevatorLoader = new ElevatorLoader(xmlElv); AllPassengers = _passengerLoader.Load(); AllElevators = _elevatorLoader.Load(); NaiveScheduler = Scheduler.SchedulerFactory.CreateScheduler(); foreach (SenElevator elev in AllElevators) { elev.Scheduler = NaiveScheduler; } List<IElevator> elevs = new List<IElevator>(); foreach (IElevator e in AllElevators) elevs.Add(e); NaiveScheduler.Initialize(elevs); // SenElevator.SenClock.Start(AllElevators); TickGoes = new Thread(new ThreadStart(this.WorldEngine)); TickGoes.Start(); } void TickUpdate(int nextActiveTick) { if (AreElevatorsIdle() && nextActiveTick > ticks) { ticks = nextActiveTick; } else { ticks++; } } void WorldEngine() { while (true) { Console.WriteLine("Tick #{0}-------------------------------", ticks); if (ElevUpdate != null) foreach (IElevator e in AllElevators) ElevUpdate(e, new EventArgs()); int NextActiveTick = -1; bool complete = DrivePassenger(ref NextActiveTick); if (complete) break; DriveElevator(); NaiveScheduler.Run(); TickUpdate(NextActiveTick); Console.WriteLine(""); } } bool DrivePassenger(ref int NextActiveTick) { bool complete = true; bool active = false; int nextTick = 0x7fffffff; foreach (SigmaPassenger p in AllPassengers) { if (!p.IsArrived) { complete = false; } IRequest req = p.GenerateReq(ticks, AllElevators.ConvertAll<IElevator>(o=>o)); if (req != null) { NaiveScheduler.QueueReq(req); active = true; } if (p.IsInside) active = true; else { if (!p.IsArrived) { nextTick = Math.Min(nextTick, p.DirectionReqTime); } } } if (!active) NextActiveTick = nextTick; return complete; } void DriveElevator() { foreach (SenElevator elev in AllElevators) { elev.StatusUpdateForEveryTick(ticks); } } static void RealTimeTest( List<SenElevator> Elevs, List<SigmaPassenger> Passengers, IScheduler Scheduler ) { //int i = 0; //while (i < Passengers.Count) //{ // IPassenger p = Passengers[i]; // SenElevator.SenClock.Wait(p.DirectionReqTime); // lock (SenElevator.SenClock) //stop the clock // { // do // { // Scheduler.QueueDirection(p); // i++; // } while (i < Passengers.Count && Passengers[i].DirectionReqTime == p.DirectionReqTime); // } //} } static void SimulateTimeTest( List<SenElevator> Elevs, List<SigmaPassenger> Passengers, IScheduler Scheduler) { //foreach (IPassenger p in Passengers) //{ // Scheduler.QueueDirection(p); //} //Scheduler.Run(); } static void Main(string[] args) { Program program = new Program(); if (args.Count() != 2) { Console.WriteLine("usage:"); Console.WriteLine(" world.exe elevators.xml passengers.xml"); return; } program.WorldInit(args[0], args[1]); //do //if (args.Length >= 1 && // !string.IsNullOrEmpty(args[0]) && // args[0].Equals("r", StringComparison.CurrentCultureIgnoreCase)) //{ // RealTimeTest(AllElevators, AllPassengers, NaiveScheduler); //} //else //{ // SimulateTimeTest(AllElevators, AllPassengers, NaiveScheduler); //} program.TickGoes.Join(); int num = 0; int cost = 0; foreach (SigmaPassenger p in AllPassengers) { p.PrintStatistics(); cost += p.ReqCompleteTime - p.DirectionReqTime; num++; } Console.WriteLine("average cost {0}", (float)cost / num); } } }
运行界面如图:(显示了有上升停止,下降可以显示只不过当前截图未在有下降执行期间截图)
附加题3:UI界面设计如附加题2中所展示。其让在控制台依照预设逻辑及传入参数跑的同时可以有一个界面显示当前程序的状态。UI界面即是MVC中的用户界面,我的主程序相当于我的M即业务模型。附加题2中的Program即是保证M与V同步的控制器C。用户界面允许用户用不同的数据操作。业务模型可以保证操作的正确性及一定的效率性。控制程序则对相应的数据及界面输出做调整决策。在现实中可减少代码重复性,及整体的实用性。但只是MVC实现还是有些复杂。对于电梯的状态如当前层数及行驶方向参数我们将其解耦,从UI界面提供入口,相当于加了一层接口,使得不同用户可以使用同一套数据逻辑。也使得UI界面构造非常容易,有一定实力的外观设计师就可构造更亮丽的界面。同时低耦合也使得整体程序有很强的可测试性。
附加题4:现实生活中一座楼中的多部电梯可能可到达楼层不为全部楼层。如各个位置会根据人员需求做相应调整成分段电梯或者较高楼层会有接力电梯等。在这种条件下。我们就需要在源代码中的各种需求进行更多的判定及相应的转换。
基于现有提供的乘客需求信息形式,我们小队认为应对程序做以下修改:
1、Passenger包中应该添加用于保存乘客请求中断信息的公共类。该信息应包括乘客在当前最佳需求执行过后还需执行的请求信息及上一个中间需求的初始执行时间。
2、该包中EnterElevator()类中在乘客进入电梯时对请求是否能够实现做判定,如不能,加入中断判定记录以及相应续接的请求信息并且修改当前需求目的楼层为该方向边界楼层后再加入电梯内部需求列表。
3、依据1,2,该包中的LeaveElevator()类中离开时判定如果有乘客的需求初始执行时间及当前楼层存在于中断信息储存类中,则将保存的续接请求信息添加到需求列表中。并且到达判定不做修改。
4、在我的执行方式函数中将添加忽略判定。如果乘客需求层数不在我当前电梯可执行层数之间或者需求层数刚好等于当天电梯可执行层数的边界但是需求方向向不可执行方向就会忽略这个需求继续判定下一个需求。
5、对特定执行区间的电梯依据其有趋向性的人员流动及时作出相应反应并迅速执行对于特定时间段人员流动的执行方式。