C 裡的委託和事件實現Observer

2021-03-31 08:56:29 字數 4052 閱讀 7769

一、委託的簡介

1、委託的宣告:

delegate handlername ([parameters])

例如:public delegate void printhandler(string str);

委託宣告定義了一種型別,它用一組特定的引數以及返回型別來封裝方法。對於靜態方法,委託物件封裝要呼叫的方法。對於例項方法,委託物件同時封裝乙個例項和該例項上的乙個方法。如果您有乙個委託物件和一組適當的引數,則可以用這些引數呼叫該委託。

2、委託的使用:

using system;

public class myclass

}public delegate void printhandler(string str);    // 宣告委託型別

public class printstr

}在c#中使用委託方法:

·          建立委託所使用的方法必須和委託宣告相一致(引數列表、返回值都一致)

·          利用 +=、-=來進行委託的鏈結、取消鏈結或直接使用delegate.***bine和delegate.remove方法來實現

·          可以使用multicastdelegate的例項方法getinvocationlist()來獲取委託鏈中所有的委託

·          不能撰寫包含 out 引數的委託

二、事件的簡介

c# 中的「事件」是當物件發生某些事情時,類向該類的客戶提供通知的一種方法。

1、事件的宣告:

宣告的格式為:event eventname

因為使用委託來宣告事件,所以在類裡宣告事件時,首先必須先宣告該事件的委託型別(如果尚未宣告的話)。在上面我們已經提到過了委託型別的宣告,但是在.***  framework下為事件使用的委託型別進行宣告時有更嚴格的規定:

(1)、 事件的委託型別應採用兩個引數;

(3)、「e」引數的型別應為eventargs 類或派生自 eventargs 類。

如下的定義:

public delegate void printhandler(object sender,system.eventargs e);

然後我們才能宣告該委託型別的事件

例如:public event printhandler print;

當事件發生時,將呼叫其客戶提供給它的委託。

2、呼叫事件:

類宣告了事件以後,可以就像處理所指示的委託型別的字段那樣處理該事件。如果沒有任何客戶將委託與該事件繫結,則該字段將為空;否則該欄位引用應在呼叫該事件時呼叫的委託。因此,呼叫事件時通常先檢查是否為空,然後再呼叫事件。(呼叫事件,即觸發事件,只能從宣告該事件的類內進行)

if(print != null)

3、事件繫結:

從類的外面來看,事件就象類的乙個公共成員,通過 類名.事件名 的形式來訪問,但是只能對它做繫結和解除繫結的操作,而不能有其他操作。

類名. print += new printhandler(繫結的方法名)  // 將某個方法繫結到print事件上

類名. print  -= new printhandler(繫結的方法名)  // 將某個已繫結到print事件上的方法從print事件上解除

三、委託和事件的使用

委託和事件在使用者介面程式裡用的比較的多,比如象在winform或webform的使用者ui上的button和它的click事件:

// 將button1_click()方法繫結到按鈕控制項button1的click事件上

this.button1.click += new system.eventhandler(this. button1_click);

private void button1_click(object sender, system.eventargs e)    // button1_click()方法

然而除了使用者介面程式外,在很多其他地方也用到了事件驅動模式,比如觀察者模式(observer)或發布/訂閱(publish/subscribe)裡:在乙個類裡發布(publish)某個可以被觸發的事件,而其他的類就可以來訂閱(subscribe)該事件。一旦這個發布者類觸發了該事件,那麼執行時環境會立刻告知所有訂閱了該事件的訂閱者類:這個事件發生了!從而各個訂閱者類可以作出它們自己的反應(呼叫相應方法)。

我們來舉乙個生活中的實際例子來說明如何使用委託和事件,以及使用委託和事件所帶來的好處:

比如說有乙個公司(場景),你是老闆,手下有主管和員工,作為老闆你會指派(委託)主管管理員工的工作,如果某個員工玩遊戲,則讓某個主管從該員工的薪水裡扣去500元錢。

這就是現實中的委託。

而在寫程式中,假設程式設計師就是老闆,有兩個類分別為主管和員工,而主管小王和員工小張就是兩個類的物件例項。員工類有乙個方法:玩遊戲,同時就有乙個玩遊戲的事件,他一玩遊戲就會激發這個事件。而主管類就是負責處理該事件的,他負責把玩遊戲的員工的薪水扣除500。

(一)、首先,我們來看看在非委託的情況下比較常見的一種設計方式(當然這不是唯一的方式,也不是最好的方式,但是很常見):

using system;

namespace csharpconsole

}// 負責扣錢的人----主管

public class 主管

public void 扣薪水(員工 employee)

}// 如果玩遊戲,則會引發事件

public class 員工

public int 薪水 // 此屬性可以操作員工的薪水 。

set}

public void 玩遊戲()}}

這種方法所帶來的問題: 員工類和主管類的耦合性太高

1、   在客戶程式裡必須先建立了主管類之後才能生成員工類,如果在不需要主管類物件而只需員工類物件的地方,為了建立所需的員工類物件例項,你也不得不去先建立乙個主管類的物件例項;

2、   如果場景劇本(即客戶程式需求)發生了變化

(1)、現在要讓乙個新的角色(乙個新的類),如保安,來代替主管,負責在員工玩遊戲時扣員工薪水,那麼我們不得不去修改員工類,或許還需要修改主管類;

(2)、如果場景劇本增加新的需求,要求員工在玩遊戲後,不但要扣薪水,還要在績效上扣分,那麼我們也不得不修改員工類。

(二)、利用委託的實現:

using system;

namespace csharpconsole

public void 扣薪水(object sender,eventargs e)

}// 如果玩遊戲,則會引發事件

public class 員工

public int 薪水 // 此屬性可以操作員工的薪水 。

set}

public void 玩遊戲()

protected virtual void onplaygame(eventargs e)}}

public class 場景}}

對於前面提出的問題:

1、   解耦了主管類和員工類之間的必然聯絡,可以單獨建立員工類物件例項,而不用管是否有主管類物件例項的存在;

2、   在客戶程式需求變化時:

(1)、我們只需修改客戶程式,即上面例子裡的class 場景,將委託改為如下:

保安 小李 = new 保安();

小張.playgame += new playgamehandler(小李. 扣薪水);

即可實現由保安來負責扣薪水的需求變化,而不用動員工類。

(2)、我們只需修改客戶程式,即上面例子裡的class 場景,新增乙個如下的委託:

小張.playgame += new playgamehandler(某某. 扣績效分);

這個「某某」可以是主管,也可以是其他新的角色(新的類),只需要在「某某」對應的類裡定義扣績效分的動作即可,而不用動員工類。

四、總結:

當然,不使用委託和事件我們仍然可以設計出解耦的類,然而卻會增加很多的類、介面以及關聯等等,增加了**量和程式的邏輯複雜性,而在.***裡利用委託和事件我們只需少的多的**來實現。

委託和事件的使用有如下幾個要素:

1、激發事件的物件-----就是員工小張

2、處理物件事件的物件-----就是主管小王

3、定義委託,就是你讓主管小王監視員工小張。

如果這三個要素都滿足的話,則你就寫出了乙個完整事件的處理。

C 裡的委託和事件實現

一 委託的簡介 1 委託的宣告 delegate handlername parameters 例如 public delegate void printhandler string str 委託宣告定義了一種型別,它用一組特定的引數以及返回型別來封裝方法。對於靜態方法,委託物件封裝要呼叫的方法。對...

C 事件和委託

c 程式設計中的事件驅動是說應用程式的執行流程是由外界發生的事件確定的。也就是接受到任務再工作的模式。事件是乙個訊號,它告知應用程式有重要的事情發生。真正的執 況是,各個應用程式把負責不同功能的物件在其執行期間送入windows作業系統,讓這些物件等待windows產生事件。然後加以處理,windo...

C 委託和事件

什麼是委託?委託和事件這兩個概念是完全配合的。委託僅僅是函式指標,那就是說,它能夠引用函式,通過傳遞位址的機制完成。委託是乙個類,當你對它例項化時,要提供乙個引用函式,將其作為它建構函式的引數 先看示例 例中先申明乙個委託,例如 public delegate void somedelegate s...