国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發(fā) > 綜合 > 正文

C#里的委托和事件實(shí)現(xiàn)Observer

2024-07-21 02:19:15
字體:
供稿:網(wǎng)友
一、委托的簡介

1、委托的聲明:

<access modifier> delegate <returntype> handlername ([parameters])

例如:

public delegate void printhandler(string str);



委托聲明定義了一種類型,它用一組特定的參數(shù)以及返回類型來封裝方法。對于靜態(tài)方法,委托對象封裝要調(diào)用的方法。對于實(shí)例方法,委托對象同時封裝一個實(shí)例和該實(shí)例上的一個方法。如果您有一個委托對象和一組適當(dāng)?shù)膮?shù),則可以用這些參數(shù)調(diào)用該委托。



2、委托的使用:

using system;



public class myclass

{

public static void main()

{

printstr myprinter = new printstr();

printhandler myhandler = null;

myhandler += new printhandler(myprinter.callprint); // 將委托鏈接到方法,來實(shí)例化委托

if(myhandler!=null)

myhandler("hello world!"); // 調(diào)用委托,相當(dāng)于匿名調(diào)用委托所鏈接的方法

console.read();

}

}



public delegate void printhandler(string str); // 聲明委托類型



public class printstr

{

public void callprint(string input)

{

console.writeline(input);

}

}






在c#中使用委托方法:

· 創(chuàng)建委托所使用的方法必須和委托聲明相一致(參數(shù)列表、返回值都一致)

· 利用 +=、-=來進(jìn)行委托的鏈接、取消鏈接或直接使用delegate.combine和delegate.remove方法來實(shí)現(xiàn)

· 可以使用multicastdelegate的實(shí)例方法getinvocationlist()來獲取委托鏈中所有的委托

· 不能撰寫包含 out 參數(shù)的委托



二、事件的簡介

c# 中的“事件”是當(dāng)對象發(fā)生某些事情時,類向該類的客戶提供通知的一種方法。

1、事件的聲明:

聲明的格式為:<access modifier> event <delegate type> eventname



因?yàn)槭褂梦衼砺暶魇录栽陬惱锫暶魇录r,首先必須先聲明該事件的委托類型<delegate type>(如果尚未聲明的話)。在上面我們已經(jīng)提到過了委托類型的聲明,但是在.net framework下為事件使用的委托類型進(jìn)行聲明時有更嚴(yán)格的規(guī)定:

(1)、 事件的委托類型應(yīng)采用兩個參數(shù);

(2)、兩個參數(shù)分別是:指示事件源的“對象源”參數(shù)和封裝事件的其他任何相關(guān)信息的“e”參數(shù);

(3)、“e”參數(shù)的類型應(yīng)為eventargs 類或派生自 eventargs 類。

如下的定義:

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



然后我們才能聲明該委托類型的事件

例如:

public event printhandler print;

當(dāng)事件發(fā)生時,將調(diào)用其客戶提供給它的委托。



2、調(diào)用事件:

類聲明了事件以后,可以就像處理所指示的委托類型的字段那樣處理該事件。如果沒有任何客戶將委托與該事件綁定,則該字段將為空;否則該字段引用應(yīng)在調(diào)用該事件時調(diào)用的委托。因此,調(diào)用事件時通常先檢查是否為空,然后再調(diào)用事件。(調(diào)用事件,即觸發(fā)事件,只能從聲明該事件的類內(nèi)進(jìn)行)



if(print != null)

{

print (this,e);

}



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()方法

{

……

}



然而除了用戶界面程序外,在很多其他地方也用到了事件驅(qū)動模式,比如觀察者模式(observer)或發(fā)布/訂閱(publish/subscribe)里:在一個類里發(fā)布(publish)某個可以被觸發(fā)的事件,而其他的類就可以來訂閱(subscribe)該事件。一旦這個發(fā)布者類觸發(fā)了該事件,那么運(yùn)行時環(huán)境會立刻告知所有訂閱了該事件的訂閱者類:這個事件發(fā)生了!從而各個訂閱者類可以作出它們自己的反應(yīng)(調(diào)用相應(yīng)方法)。



我們來舉一個生活中的實(shí)際例子來說明如何使用委托和事件,以及使用委托和事件所帶來的好處:



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

這就是現(xiàn)實(shí)中的委托。

而在寫程序中,假設(shè)程序員就是老板,有兩個類分別為主管和員工,而主管小王和員工小張就是兩個類的對象實(shí)例。員工類有一個方法:玩游戲,同時就有一個玩游戲的事件,他一玩游戲就會激發(fā)這個事件。而主管類就是負(fù)責(zé)處理該事件的,他負(fù)責(zé)把玩游戲的員工的薪水扣除500。



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



using system;

namespace csharpconsole

{

public class 場景

{

[stathread]

public static void main(string[] args)

{

console.writeline("場景開始了.");

// 生成主管類的對象實(shí)例 小王

主管 小王 = new 主管();

// 生成員工類的對象實(shí)例 小張,指定他的主管

員工 小張 = new 員工(小王);



console.writeline("該員工本有的薪水:" + 小張.薪水.tostring());



// 員工開始玩游戲

小張.玩游戲();



console.writeline("現(xiàn)在該員工還剩下:" +小張.薪水.tostring());



console.writeline("場景結(jié)束");

console.readline();

}

}







// 負(fù)責(zé)扣錢的人----主管

public class 主管

{

public 主管()

{

console.writeline("生成主管");

}



public void 扣薪水(員工 employee)

{

console.writeline("主管:好小子,上班時間膽敢玩游戲");

console.writeline("主管:看看你小子有多少薪水");



console.writeline("開始扣薪水...");

system.threading.thread.sleep(1000);



employee.薪水 = employee.薪水 - 500;



console.writeline("扣薪水執(zhí)行完畢.");

}

}



// 如果玩游戲,則會引發(fā)事件

public class 員工

{

// 保存員工的薪水

private int m_money;

// 保存該員工的主管

private 主管 m_manager;



public 員工(主管 manager)

{

console.writeline("生成員工.");

m_manager = manager; // 通過構(gòu)造函數(shù),初始化員工的主管。

m_money = 1000; // 通過構(gòu)造函數(shù),初始化員工的薪水。

}



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

{

get

{

return m_money;

}

set

{

m_money = value;

}

}



public void 玩游戲()

{

console.writeline("員工開始玩游戲了..");

console.writeline("員工:cs真好玩,哈哈哈! 我玩...");

system.threading.thread.sleep(1000);



m_manager. 扣薪水(this);

}

}

}



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

1、 在客戶程序里必須先創(chuàng)建了主管類之后才能生成員工類,如果在不需要主管類對象而只需員工類對象的地方,為了創(chuàng)建所需的員工類對象實(shí)例,你也不得不去先創(chuàng)建一個主管類的對象實(shí)例;

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

(1)、現(xiàn)在要讓一個新的角色(一個新的類),如保安,來代替主管,負(fù)責(zé)在員工玩游戲時扣員工薪水,那么我們不得不去修改員工類,或許還需要修改主管類;

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


(二)、利用委托的實(shí)現(xiàn):



下面有個例子:在c# 控制臺應(yīng)用程序編輯運(yùn)行成功:



using system;

namespace csharpconsole

{

// 定義委托

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



// 負(fù)責(zé)扣錢的人----主管

public class 主管

{

public 主管()

{

console.writeline("生成主管");

}



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

{

console.writeline("主管:好小子,上班時間膽敢玩游戲");

console.writeline("主管:看看你小子有多少薪水");



員工 employee = (員工)sender;



console.writeline("開始扣薪水...");

system.threading.thread.sleep(1000);

employee.薪水 = employee.薪水 - 500;

console.writeline("扣薪水執(zhí)行完畢.");

}

}



// 如果玩游戲,則會引發(fā)事件

public class 員工

{

// 先定義一個事件,這個事件表示員工在玩游戲。

public event playgamehandler playgame;

// 保存員工薪水的變量

private int m_money;



public 員工()

{

console.writeline("生成員工.");

m_money = 1000; // 構(gòu)造函數(shù),初始化員工的薪水。

}



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

{

get

{

return m_money;

}

set

{

m_money = value;

}

}



public void 玩游戲()

{

console.writeline("員工開始玩游戲了..");

console.writeline("員工:cs真好玩,哈哈哈! 我玩...");

system.threading.thread.sleep(1000);

system.eventargs e = new eventargs();



onplaygame(e);

}



protected virtual void onplaygame(eventargs e)

{

if(playgame != null)

{

playgame(this,e);

}

}

}



public class 場景

{

[stathread]

public static void main(string[] args)

{

console.writeline("場景開始了.");

// 生成主管類的對象實(shí)例 小王

主管 小王 = new 主管();

// 生成員工類的對象實(shí)例 小張

員工 小張 = new 員工();



// 設(shè)下委托,指定監(jiān)視

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



console.writeline("該員工本有的薪水:" + 小張.薪水.tostring());



// 員工開始玩游戲

小張.玩游戲();



console.writeline("現(xiàn)在該員工還剩下:" +小張.薪水.tostring());



console.writeline("場景結(jié)束");

console.readline();

}

}

}




對于前面提出的問題:

1、 解耦了主管類和員工類之間的必然聯(lián)系,可以單獨(dú)創(chuàng)建員工類對象實(shí)例,而不用管是否有主管類對象實(shí)例的存在;

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

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



保安 小李 = new 保安();

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



即可實(shí)現(xiàn)由保安來負(fù)責(zé)扣薪水的需求變化,而不用動員工類。

(2)、我們只需修改客戶程序,即上面例子里的class 場景,添加一個如下的委托:



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



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



四、總結(jié):

當(dāng)然,不使用委托和事件我們?nèi)匀豢梢栽O(shè)計(jì)出解耦的類,然而卻會增加很多的類、接口以及關(guān)聯(lián)等等,增加了代碼量和程序的邏輯復(fù)雜性,而在.net里利用委托和事件我們只需少的多的代碼來實(shí)現(xiàn)。



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


1、激發(fā)事件的對象-----就是員工小張
2、處理對象事件的對象-----就是主管小王
3、定義委托,就是你讓主管小王監(jiān)視員工小張。

如果這三個要素都滿足的話,則你就寫出了一個完整事件的處理。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 平江县| 岳普湖县| 墨江| 云南省| 温泉县| 德阳市| 康保县| 徐汇区| 虹口区| 霍城县| 明星| 大洼县| 赞皇县| 海林市| 大同县| 南岸区| 金昌市| 社旗县| 隆化县| 鱼台县| 图木舒克市| 三门峡市| 嘉荫县| 阿拉善左旗| 河池市| 哈密市| 五寨县| 红桥区| 宜君县| 淳化县| 思茅市| 崇仁县| 彰化县| 游戏| 云安县| 商水县| 怀远县| 岑巩县| 浦江县| 哈密市| 象山县|