網上有好多講委託與事件的文章,寫得都很不錯,以下是我對事件與委託的理解,若有不當之處,請提出,萬分感謝。
為了方便閱讀,我將代碼寫在了後面,前面介紹了一些跟代碼有關的資訊。
Observe模式中,主體subject指受監控者,觀察者observer指監控者。記憶體狀態(MemeryStatus)是受監控者,屬於主體;Observer是監控者,屬於觀察者;
主體中往往有一個或多個觀察者感興趣的資訊,此例中式currentVolume,即當前記憶體容量,主體中還應該有定義好的事件,主體中的事件在用戶端(一般指含有Main函數的類)與觀察者中的處理方法綁定,當主體滿足某一條件時(此例中指滿足currentVolume>95時),就應該激發事件(此例中指MemeryObserve(this, args);),之後,與該事件綁定的所有觀察者端的處理方法都會執行(這叫回調),這樣,通過事件,將主體端的狀態變化和觀察者端的監控相關聯,主體變化,觀察者就能做出相應變化了。
換種方式看本常式序,其實很熟悉,開啟VS建立一個C# Winform應用程式,在預設表單中拖放一個button控制項,雙擊該控制項,在Form1.cs中將會自動產生單擊處理常式
private void button1_Click(object sender, EventArgs e)
{
}
仔細一看,該處理方法跟本例Observer類中的 public void Warning(object sender, MemeryObserveEventArgs args)很相似最後一個參數稍微有些差別,這是因為各自訂的事件參數不同, 在void Warning(object sender, MemeryObserveEventArgs args)中,我們要獲得subject(主體)的當前容量,即currentVolume,而在void button1_Click(object sender, EventArgs e)中,我們可能 要擷取其他與subject有關的資訊,開啟Form1.Designer.cs檔案,展開"Windows 表單設計器產生的程式碼"你會找到"this.button1.Click += new System.EventHandler(this.button1_Click)"這句代碼,再仔細一看,你會發現它跟本例寫過的 status.MemeryObserve+=new MemeryObserveEventHandler(observer.Warning);這句很相似。我們知道,MemeryObserveEventHandler是我們定義的一個委託,它的方法簽名要求這樣的形式"void 函數名(object param1,MemeryObserveEventArgs param2)",那麼,System.EventeHandler其實也是個委託,類似這樣定義:public delegate void EventHandler(object sender,EventArgs args).所以,button類就是Observer模式中的主體,相當於本例 中的MemeryStatus類 ,this.button1相當於本例中的status(事件發行者),Form1(即表單類)就相當於本例中的observer(觀察者)。這樣,觀察者(Form1)觀察被觀察者(Button)的狀態變化(比如被單擊),作出相應的動作(執行void Warning(object sender, MemeryObserveEventArgs args))。
我們現在來比較一下本常式序和建立winform預設程式
1、本例中主體(即事件發行者)為MemeryStatus類,winform中的主體為Button類;
2、本例中事件為MemeryObserve,winform中事件為Click;
3、本例中事件參數類為MemeryObserveEventArgs,winform中事件參數類為EventArgs;
4、本例中觀察者(即事件訂閱者)為Observer類,winform中觀察者為表單,即Form1類;
5、本例中當事件發生,回呼函數為 public void Warning(object sender, MemeryObserveEventArgs args) ,winform中回呼函數為private void button1_Click(object sender, EventArgs e);
6、本例中當記憶體已用容量大於95時,觸發事件MemeryObserve,winform中當使用者點擊按鈕時,觸發事件Click;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public class MemeryObserveEventArgs : EventArgs //事件參數類
{
private readonly int currentVolume;
public int CurrentVolume
{
get
{
return currentVolume;
}
}
public MemeryObserveEventArgs(int C)
{
this.currentVolume = C;
}
}
public delegate void MemeryObserveEventHandler(object sender,MemeryObserveEventArgs args); //委託
public class MemeryStatus //subject,主體/publisher,事件發行者
{
private int currentVolume;
public event MemeryObserveEventHandler MemeryObserve; //定義待激發事件
public int CurrentVolume
{
get
{
return currentVolume;
}
set
{
if (value > 95) //給執行個體currentVolume賦值,如果當前已用容量大於95,則激發事件MemeryObserve
{
currentVolume = value;
if (MemeryObserve != null) //如果事件有方法綁定
{
MemeryObserveEventArgs args=new MemeryObserveEventArgs(value); //構建事件參數
MemeryObserve(this, args); //激發事件
}
}
}
}
}
public class Observer //觀察者,observer/事件訂閱者
{
public void Warning(object sender, MemeryObserveEventArgs args) //observer方的處理方法,應和前面聲明的委託有同樣的方法簽名
{
Console.Write("當前容量超過上限容量{0}\n", args.CurrentVolume);
}
}
class Program //用戶端
{
static void Main(string[] args)
{
MemeryStatus status = new MemeryStatus(); //建立subject執行個體
Observer observer = new Observer(); //建立observer執行個體
status.MemeryObserve+=new MemeryObserveEventHandler(observer.Warning); //將observer方的處理方法(observer.Warning)綁定到subject方(status.MemeryObserve)事件
for (int i = 1; i < 100; i++)
{
status.CurrentVolume = i; //以此增加subject方的當前容量,當滿足一定條件時,會激發subject方的事件
}
Console.Read();
}
}
}
//輸出結果:
//當前容量超過上限容量96
//當前容量超過上限容量97
//當前容量超過上限容量98
//當前容量超過上限容量99
//本代碼在VS2008中運行通過