Henry 譯 (2002.10.14) [Henry注: 本文并不復雜,可以為.net" name="description" />

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • Henry手記—使用TemplateMethod設計模式的.NET事件處理機制(一)

    發表于:2007-05-25來源:作者:點擊數: 標簽:Henry手記使用
    Henry手記—使用Template Method設計模式的 .NET事件處理機制(一) By Kevin McFarlane MI LY: 宋體; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'"> Henry 譯 (2002.10.14) [Henry注: 本文并不復雜,可以為.net

                     Henry手記—使用Template Method設計模式的

                                        .NET事件處理機制(一)

                                             By Kevin McFarlane

    MILY: 宋體; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">                         Henry 譯(2002.10.14)

      

       [Henry注: 本文并不復雜,可以為.net事件處理的中級讀物。本文雖為翻譯,但并不是完全精確之譯文,加入了Henry自己的看法,如有謬誤,責任在Henry矣]

     

    1.      引言

    Microsoft .NET事件處理,和標準的面向對象架構一樣,使用的是著名的Observer設計模式(請參看書籍《設計模式(Design Patterns), Gamma et al., Addison-Wesley, 1995, pp325-330)。本文描述了如何利用Template MethodHenry注:模板方法,總覺得不翻出來更親切)設計模式去增強.NET的事件處理機制。討論與代碼片斷是基于C#的,但結論示例是使用了C#Visual Basic.NET分別實現的。

    本文討論的思想是出自于Tomas Restrepo20023月出版的《Visual Systems Journal,該文是基于Microsoft MSDN Library.NET專題提供的標準事件處理示例:《 Design Guidelines for Class Library Developers (詳見文中的 "事件使用向導"一節)。

    對于事件處理,最簡單的設計就是如何觸發一個事件,而不是關心誰來執行它,或不同的使用者是否需要用不同的方法來關聯它。

    2.       示例簡單的事件處理

     設有這樣一個類:Supplier,當它的name成員被設置就會觸發一個事件,而類Client就用于處理它。

    public class Supplier
    {
        public Supplier() {}
        public event EventHandler NameChanged;  [H]
        public string Name
        {
            get { return name; }
            set { name = value; OnNameChanged(); }  [H]
        }
        private void OnNameChanged()
        {
            // 在注冊后,使用者即可觸發此事件
            if (NameChanged != null)
                NameChanged(this, new EventArgs());
        }
        private string name;
    }
    public class Client
    {
        public Client()
        {
            //  supplier 事件注冊
            supplier = new Supplier();
            supplier.NameChanged += new EventHandler( _
    this.supplier_NameChanged); [H]
        } 
        public void TestEvent()
        {
            // 設置Name,產生一個事件
            supplier.Name = "Kevin McFarlane";
        }
         private void supplier_NameChanged(object sender, _
     EventArgs e) [H]
        {
            // 處理supplier事件
        }
    private Supplier supplier;
    }

    [Henry注:在此示例中,我們同時可以學習一下在C#中自定義一個事件,并處理它的方法。請注意我標上[H]的代碼]。

    一個事件的使用者即可以是外部的,也可以是內部的。

    一個“外部的”使用者是指可以執行一個事件,但與觸發此事件的類并無關系。換句話說,它不是事件類繼承樹中的一部分。示例中的Client類就是一個外部使用者。

    一個“內部的”使用者可以是事件發生類自身(如果它同時處理自已的事件的話),或是該事件發生類的一個派生類。對于這種情況,上文所說的簡單的設計就不夠充分了。用戶不能很方便地改變當事件被觸發后要發生的變化,或是處理事件的默認行為了。

    為了應付這個問題,在.NET Design Guidelines for Class Library Developers一文中,Microsoft推薦使用一個保護的Virtual Method(虛方法)去觸發每個事件。這就提供給子類一個通過重寫來處理事件的方法。因此,在我們的示例中,OnNameChanged()應該象下例這樣寫:

    protected virtual void OnNameChanged()
    {
        // 在注冊后,使用者即可觸發此事件
        if (NameChanged != null)
            NameChanged(this, new EventArgs());
    }

    Microsoft隨即說:“派生類在處理OnEventNameHenry注:OnEventName即類似于OnNameChanged的事件觸發方法),可選擇不調用基類。要這么做就得在OnEventName方法中不包含任何處理過程以利于基類正確地工作?!?/SPAN>

    這有一個問題,一般來說,OnNameChanged()在觸發事件前可以做一些默認的處理。重寫OnNameChanged()可以實現不同的處理過程。但是為保證外部的使用者工作正常,它必須調用基類。如果它不能調用基類,該事件就不能為外部使用者所用。忘記調用觸發事件的基類,就違背了Liskov的多態替代原則(Henry注:出自麻省理工學院(MIT)計算機科學實驗室的Barbara Liskov女士發表的經典文章Data Abstraction and Hierarchy,本文原作者做了小改動):使用指向基類的引用的方法,必須能夠在不知道具體派生類對象類型的情況下使用它們。幸運的是,現在有一個解決的方法。

    3.      Template Method設計模式

    Template Method設計模式的目的是定義一個算法作為固定的操作步驟,但有一個或多個步驟可以有變化。Henry注:變化通常是指將某些步驟延遲到子類中去描述與執行)在我們的示例中,算法可認為是由觸發事件及其響應來組成。需要有變化的地方就是響應。因此決竅就在于將它從事件觸發中分離出來。我們將OnNameChanged()分割成兩個方法:InternalOnNameChanged() OnNameChanged()。InternalOnNameChanged()調用OnNameChanged()來執行默認的處理,然后觸發事件。

    private void InternalOnNameChanged()
    {
        //派生類可重寫默認的行為
        OnNameChanged();
        // 在注冊后,使用者即可觸發此事件
        if (NameChanged != null)
            NameChanged(this, new EventArgs());
    }
     
    protected virtual void OnNameChanged()
    {
        //在此執行默認的行為
    }

    Name屬性改為:

    get { return name; }
    set { name = value; InternalOnNameChanged(); }

    使用這種方法的好處在于:

    1)                  在這個觸發事件的示例中,它是基類執行的重要步驟以避免派生類調用基類執行的失敗。因此外部使用者可以獲得更為可靠的服務;

    2)                  派生類可毫不用擔心,在OnNameChanged()安全地替換基類的默認行為。

     

    e-mail: ruigeren@sina.com

    QQ: 18349592

    ----

      聲明:本文版權與解釋權歸韓睿所有,如需轉載,請保留完整的內容及此聲明。

    原文轉自:http://www.kjueaiud.com

    評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>