小序:
工作中最大的挑戰並不是那些Mission Impossible,而是你需要一邊保持安靜、平衡的心態以專注於工作,一邊對抗公司體制、社會經濟和人際環境對這種心態的破壞——這是對兒永遠也解不開的矛盾。
正文:
記得我在前面一篇文章裡提到過:壘磚頭壘多少年也成不了建築師——仍然只會砌牆。同樣,堆控件堆多少年也成不了程序員——仍然只會拼湊窗體。成為建築師的關鍵在於學習建築的結構,成為程序員的關鍵則在於了解程序的結構。今天,就讓我們告別在窗體上堆控件,剖析一下窗體與窗體上控件關系——特別是事件的由來以及事件激發Event Fire)與事件響應Event Handling)之間的聯系。
事件的由來
傳統的面向對象概念中是沒有事件Event)這個東西的,有的只是值域Field)和方法Method)。那麼事件又是怎麼來的呢?在傳統的面向對象編程中,如果一個類想調用另一個類的方法,程序員有兩種方法:
1. 在一個類的方法裡通過另一個類的方法名進行直接調用,看上去會是這樣:
#include <iostream>
class A
{
public:
void Method()
{
std::cout<<"This is A."<<std::endl;
}
};
class B
{
public :
void Method(A arg)
{
arg.Method(); // B與A緊密耦合在一起
}
};
int main(int argc, char *argv[])
{
A a;
B b;
b.Method(a);
return 0;
}
這樣做的好處在於程序結構相當簡單,但為這種“簡單”所付出的代價就是——類與類之間耦合過於緊密,而使程序幾乎不具有彈性和可伸縮性——於是有了另一種方法。
2. 在主調類裡保有一個函數指針,並將這個指針指向一個函數,在這個函數裡再調用其它類的方法。喔~~~你可能會問:“干嗎不讓這個指針直接指向其它類的方法,還要再借助一個中間函數做跳板呢?”呵呵,答案是:函數指針是不能指向類的成員函數的——《C++必知必會》裡有詳細解釋,如果想再深挖一些,還可以看《深入探索C++對象模型》。這也就是我們常說的“間接引用”或者聞名遐迩的“回調函數”啦:D 大概的樣子如下:
#include <iostream>
class A
{
public:
void Method()
{
std::cout<<"This is A."<<std::endl;
}
};
typedef void (*FunctionPointer)(); // 把函數指針定義成一種“類型”
class B
{
public :
FunctionPointer funPointer; // 聲明一個函數指針成員,必需與將被調用的方法類型保持一致
void Method()
{
funPointer(); // 通過函數指針來調用目標方法,B類不與任何類明確耦合
}
};
void Function() // 將被間接調用的函數
{
A a;
a.Method();
}
int main(int argc, char *argv[])
{
B b;
b.funPointer = Function; // 成員指針與函數綁定,不存在類與類耦合的問題
b.Method(); // 主調函數-->跳板函數-->被調函數
return 0;
}
這個模型真的非常不錯!而且在C/C++世界廣為流傳。然而,時過境遷,隨著.NET時代的來臨和指針的不安全性程序crash和內存洩漏之母:p)日益為人诟病,C#最終放棄了指針——確切地講是“囚禁”了指針。雖然放棄了指針,但C#並沒有放棄這種通過間接調用而降低類間耦合度的模型。微軟是怎樣做到的呢?原來,微軟為.NET Framework添加了一種新的數據類型——委托Delegate)。
作為一種新的引用型數據類型,委托是一種類。既然是類,就沒辦法直接當作類的成員來使咯,所以能當作類成員來使用的只能是委托的實例聽起來真的是廢話~~但很多初學的朋友就是在這裡卡殼)。作為類的成員,委托的實例用起來的確很像函數指針,所以,我不得不再糾正一個流傳甚廣的謬誤——有人說委托是函數指針的升級或委托是“超級函數指針”——實際上應該說委托的實例是函數指針的升級、委托的實例是“超級函數指針”。
對於“超級函數指針”這個title,委托的實例是當之無愧的。它除了可以像函數指針那樣“掛接”一個方法函數被封裝在類裡之後就稱之為“方法”了)外,功能大大超越了函數指針,這體現在:
本文出自 “上善若水 潤物無聲” 博客,請務必保留此出處http://liutiemeng.blog.51cto.com/120361/29552