程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 深入淺出話窗體(一)——窗體事件模型(上)

深入淺出話窗體(一)——窗體事件模型(上)

編輯:關於C語言

小序:             工作中最大的挑戰並不是那些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,委托的實例是當之無愧的。它除了可以像函數指針那樣“掛接”一個方法函數被封裝在類裡之後就稱之為“方法”了)外,功能大大超越了函數指針,這體現在:

  • 每個函數指針只能掛接一個目標函數,而委托的實例可以使用重載了的+=操作符肆意掛接N多方法,並美其名曰“多播委托”。
  • 函數指針具有指針的多種“通病”,而委托作為一種.NET托管類變得非常安全而馴服。
  • 函數指針不能指向類的成員函數,委托卻可以指向類的成員函數——這倒不是委托的功勞,根本原因在於C#是完全面向對象的語言,所有函數都必須封裝在類裡變成成員函數不再有散落在類之外的全局函數),如果委托不能指向成員函數,那委托還有什麼用呢:p
        如果閣下想對委托探個究竟,我推薦你去閱讀在下的掘文《深入淺出話委托》。             OK,被C#粉飾一新的間接調用模型看上去會是這樣:      //=<水之真谛>=出品,[url]http://blog.csdn.net/FantasiaX[/url]
using System;

delegate void MyDelegate();           // 聲明委托這種類的方法與聲明常規類不太一樣
                                                             // 它看上去更像是在聲明“一個函數指針”,這也正是我上面說的混淆之源。
                                                             // 從語義上講,這句與上面C++代碼中使用typedef把函數指針定義為一種類型是一致的

class A
{
         public void Method(string name)
         {
                   Console.WriteLine("Hello, {0}!", name);
         }
}

class B
{
         public MyDelegate deleInstance;                  // 聲明一個MyDelegate作為成員
         public void Method()
         {
                   if (this.deleInstance != null)                  // 安全檢驗,這是函數指針做不到的
                   {
                            this.deleInstance();
                   }
         }
}

class Program
{
         static void Function()                                       // 作為跳板的函數,將被掛接在委托的實例上
         {
                   A a = new A();
                   a.Method("Tim");
         }

         static void Main(string[] args)
         {
                   B b = new B();
                   b.deleInstance += new MyDelegate(Function);             // 創建實例,同時綁定。被綁定的函數返回值和參數類型必須與委托完全一致
                   b.Method();
         }
}
   
        你可能會問:干嗎不把委托設計成與A的Method方法類型一致、再到B類中聲明一個實例呢?這樣不就可以拋開那個什麼“當作跳板的函數”、直接調用A類實例的Method方法了嗎?             主意不錯!但請你考慮這樣一個問題:根據客戶需求和業務邏輯的需要,A類可能具有幾百個參數和返回值類型千奇百怪的方法,那麼,你打算專門針對A類開發出幾百種委托類型嗎?就算你開發出來了,B類的設計人員就樂意為B類聲明上如此一大摞專門針對A類的委托實例嗎?如果創建B類的程序員接納了針對A類的幾百個委托,那麼從針對C到Z這些類的委托呢——要不要也接納進來?不接納——除非A和B是兩口子;接納——那B類的代碼長度估計不會低於央視大樓!況且,A類、B類以及其它類的設計人員可能根本就不在一個公司、不在一起工作,怎麼可能“串通”起來做這種把類耦合在一起的浩大工程呢:p              說了半天光說委托了,事件呢?其實,事件是微軟對委托這個概念的進一步升級。就代碼而言,事件僅僅是在委托的基礎上向前邁進了一小步,但是從程序邏輯的角度上觀察,事件卻是在思想上向前邁進了一大步!為什麼這樣講呢?且聽下回分解。      TO BE CONTINUE     敬請關注:深入淺出話窗體二)——窗體事件模型下)           法律聲明:本文章受到知識產權法保護,任何單位或個人若需要轉載此文,必需保證文章的完整性未經作者許可的任何刪節或改動將視為侵權行為)。若您需要轉載,請務必注明文章出處為BKJIA以保障網站的權益;請務必注明文章作者為劉鐵猛[url]http://liutiemeng.blog.51cto.com[/url]),並向[email protected]發送郵件,標明文章位置及用途。轉載時必須將此法律聲明一並轉載。保護知識產權,人人有責,謝謝!

本文出自 “上善若水 潤物無聲” 博客,請務必保留此出處http://liutiemeng.blog.51cto.com/120361/29552

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved