在"實現觀察者模式(Observer Pattern)的2種方式"中,曾經通過接口的方式、委托與事件的方式實現過觀察者模式。本篇體驗使用Action實現此模式,並從中體驗委托與事件的區別。
□ 使用Action實現觀察者模式
就舉一個足球場上的例子,當裁判吹響終場哨,勝隊慶祝,失敗隊落寞。把裁判看作是被觀察者,比賽中的兩隊看作是觀察者。
裁判作為被觀察者需要提供一個Action委托供觀察者方法注冊。
public class Referee{public Action DoSth;public void ISayGameOver(){Console.WriteLine("嘀嘀嘀......比賽結束了~~");DoSth();}}
勝利的隊和失敗的隊擁有共同的基類。
public class Team{private string _name;public Team(string name){_name = name;}public string Name{get { return _name; }}}
勝利隊或失敗隊,作為觀察者,必須有符合Referee中Action定義的方法。
public class WinTeam : Team{public WinTeam(string name) : base(name){}public void Celebrate(){Console.WriteLine("我們晉級了,好開心!");}}public class LoseTeam : Team{public LoseTeam(string name) : base(name){}public void WeAreSad(){Console.WriteLine("比賽輸了,好傷心!");}}
客戶端,先把失敗隊和勝利隊的方法注冊到Action變量,然後由被觀察者的一個方法觸發委托鏈和方法。
static void Main(string[] args){Referee referee = new Referee();var winTeam = new WinTeam("勝利隊");var loseTeam = new LoseTeam("失敗隊");//注冊觀察者referee.DoSth += winTeam.Celebrate;referee.DoSth += loseTeam.WeAreSad;//被觀察者啟動事件通知觀察者referee.ISayGameOver();}
□ 體驗委托與事件的區別
現在,我們在客戶端,在調用Referee的實例方法ISayGameOver之前,嘗試把Referee的委托變量DoSth設置為null。
static void Main(string[] args){Referee referee = new Referee();var winTeam = new WinTeam("勝利隊");var loseTeam = new LoseTeam("失敗隊");//注冊觀察者referee.DoSth += winTeam.Celebrate;referee.DoSth += loseTeam.WeAreSad;referee.DoSth = null;//被觀察者啟動事件通知觀察者referee.ISayGameOver();}
可見,當把把Referee的委托變量DoSth設置為null後,所有注冊的方法將得不到執行。
如果把Referee的委托變量DoSth修飾為事件。
public class Referee{public event Action DoSth;public void ISayGameOver(){Console.WriteLine("嘀嘀嘀......比賽結束了~~");if (DoSth != null){DoSth();}}}
可見,當把委托變量DoSth修飾為事件後,只能通過+=和-=注冊、取消方法,不能通過=設置。
把referee.DoSth = null;注釋掉,將不會報錯。
“委托、Lambda表達式、事件系列”包括:
委托定義如下:復制代碼 代碼如下:public class SocketSp{public delegate void ReceiveCompleted(byte[] receiveBuffer, int receiveTotalLen,Exception ex);public ReceiveCompleted receiveCompleted;}掛接方定義如下復制代碼 代碼如下:public class LinkOuter{SocketSp linkOuterSocket = new SocketSp();private void test(Socket requestHandleSocket){//此處要掛接 linkOuterSocket.receiveCompleted 事件,同時想將參數requestHandleSocket傳入,以便後續處理。}}第一個想法是利用delegate,但是失敗了。因為雖然掛接上去了,委托傳進的參數丟了,無法進行後續操作。復制代碼 代碼如下:private void test(Socket requestHandleSocket){linkOuterSocket.receiveCompleted += delegate {//To do};}第二個想法是利用Action,結果也失敗了。IDE提示委托Action未采用3個參數。復制代碼 代碼如下:private void test(Socket requestHandleSocket){linkOuterSocket.receiveCompleted += (Action)((outerReceiveBuffer, totalLen, ex) => {//To do});}第三個想法是利用lambda表達式,先與委托掛接,同時利用局部變量的調用,來實現參數傳遞到sendResponse函數中,以便後續操作。復制代碼 代碼如下:private void test(Socket requestHandleSocket){linkOuterSocket.receiveCompleted += new SocketSp.ReceiveCompleted((outerReceiveBuffer,totalLen,ex) =>{byte[] realOuterReceiveBuffer = new byte[totalLen];Array.Copy(outerReceiveBuffer, 0, realOuterReceiveBuffer, 0, totalLen);sendResponse(requestHandleSocket, realOuterReceiveBuffer,"200 OK", "text/html");});}最終用lambda表達式實現了。您可能感興趣的文章:C#用Lambda和委托實現模板方法
new Action(
() => WatchOutput.Items.Insert(
0,string.Format(formatString,parameters)))
可以看作是:
void Action1()
{
WatchOutput.Items.Insert(
0,string.Format(formatString,parameters))
}
匿名委托的好處就是,可以直接使用方法內的變量,比如formatString和parameters。