class Boss { ??? public void WorkStarted() { /* 老板不關心。 */ } ??? public void WorkProgressing() { /*老板不關心。 */ } ??? public int WorkCompleted() { ??????? Console.WriteLine(“時間差不多!”); ??????? return 2; /* 總分為10 */ ??? } }
class Universe { ??? static void Main() { ??????? Worker peter = new Worker(); ??????? Boss boss = new Boss(); ??????? peter.Advise(boss); ??????? peter.DoWork();
class Boss : IWorkerEvents { ??? public void WorkStarted() { /* 老板不關心。 */ } ??? public void WorkProgressing() { /* 老板不關心。 */ } ??? public int WorkCompleted() { ??????? Console.WriteLine(“時間差不多!”); ??????? return 3; /* 總分為10 */ ??? } }
委托
不幸的是,每當彼得忙于通過接口的實現和老板交流時,就沒有機會及時通知宇宙了。至少他應該忽略身在遠方的老板的引用,好讓其他實現了IWorkerEvents的對象得到他的工作報告。(”At least he'd abstracted the reference of his boss far away from him so that others who implemented the IWorkerEvents interface could be notified of his work progress” 原話如此,不理解到底是什么意思 ) 他的老板還是抱怨得很厲害。“彼得!”他老板吼道,“你為什么在工作一開始和工作進行中都來煩我?!我不關心這些事件。你不但強迫我實現了這些方法,而且還在浪費我寶貴的工作時間來處理你的事件,特別是當我外出的時候更是如此!你能不能不再來煩我?” 于是,彼得意識到接口雖然在很多情況都很有用,但是當用作事件時,“粒度”不夠好。他希望能夠僅在別人想要時才通知他們,于是他決定把接口的方法分離為單獨的委托,每個委托都像一個小的接口方法: delegate void WorkStarted(); delegate void WorkProgressing(); delegate int WorkCompleted();
class Worker { ??? public void DoWork() { ??????? Console.WriteLine(“工作: 工作開始”); ??????? if( started != null ) started();
??????? Console.WriteLine("“工作: 工作完成”"); ??????? if( completed != null ) { ??????????? int grade = completed(); ??????????? Console.WriteLine(“工人的工作得分=” + grade); ??????? } ??? } ??? public WorkStarted started; ??? public WorkProgressing progressing; ??? public WorkCompleted completed; }
class Boss { ??? public int WorkCompleted() { ??? Console.WriteLine("Better..."); ??? return 4; /* 總分為10 */ } }
class Universe { ??? static void Main() { ??????? Worker peter = new Worker(); ??????? Boss boss = new Boss(); ??????? peter.completed = new WorkCompleted(boss.WorkCompleted); ??????? peter.DoWork();
??? static int WorkerCompletedWork() { ??????? Console.WriteLine("Universe pleased with worker's work"); ??????? return 7; ??? }
??? static void Main() { ??????? Worker peter = new Worker(); ??????? Boss boss = new Boss(); ??????? peter.completed = new WorkCompleted(boss.WorkCompleted); ??????? peter.started = new WorkStarted(Universe.WorkerStartedWork); ??????? peter.completed = new WorkCompleted(Universe.WorkerCompletedWork); ??????? peter.DoWork();
不幸的是,宇宙太忙了,也不習慣時刻關注它里面的個體,它可以用自己的委托替換了彼得老板的委托。這是把彼得的Worker類的的委托字段做成public的一個無意識的副作用。同樣,如果彼得的老板不耐煩了,也可以決定自己來激發彼得的委托(真是一個粗魯的老板): // Peter's boss taking matters into his own hands if( peter.completed != null ) peter.completed(); 彼得不想讓這些事發生,他意識到需要給每個委托提供“注冊”和“反注冊”功能,這樣監聽者就可以自己添加和移除委托,但同時又不能清空整個列表也不能隨意激發彼得的事件了。彼得并沒有來自己實現這些功能,相反,他使用了event關鍵字讓C#編譯器為他構建這些方法: class Worker { ... ??? public event WorkStarted started; ??? public event WorkProgressing progressing; ??? public event WorkCompleted completed; } 彼得知道event關鍵字在委托的外邊包裝了一個property,僅讓C#客戶通過+= 和 -=操作符來添加和移除,強迫他的老板和宇宙正確地使用事件。 static void Main() { ??? Worker peter = new Worker(); ??? Boss boss = new Boss(); ??? peter.completed += new WorkCompleted(boss.WorkCompleted); ??? peter.started += new WorkStarted(Universe.WorkerStartedWork); ??? peter.completed += new WorkCompleted(Universe.WorkerCompletedWork); ??? peter.DoWork();