大白話系列之C#委託與事件講解(三)

轉自:http://www.cnblogs.com/wudiwushen/archive/2010/04/21/1717378.htmlhtml

今天我接着上面的3篇文章來說一下,爲何咱們在平常的編程活動中遇到這麼多sender,EventArgs e 參數:
protected void Page_Load(object sender, EventArgs e)
{編程

}設計模式

protected void btnSearch_Click(object sender, ImageClickEventArgs e)
{函數

}this

protected void grdBill_RowDataBound(object sender, GridViewRowEventArgs e)
{
           
}
那他們到底表示什麼呢?編碼

在回答上面的問題以前,咱們先搞懂 .Net Framework的編碼規範:spa

1、委託類型的名稱都應該以EventHandler結束。 
2、委託的原型定義:有一個void返回值,並接受兩個輸入參數:一個Object 類型,一個 EventArgs類型(或繼承自EventArgs)。 
3、事件的命名爲 委託去掉 EventHandler以後剩餘的部分。 
4、繼承自EventArgs的類型應該以EventArgs結尾。設計

這就是微軟編碼的規範,固然這不只僅是規則,而是在這種規則下使程序有更大的靈活性,那咱們就繼續重構第三講的例子,讓他符合微軟的規範。code

複製代碼
代碼
    //全部訂閱者【Subscriber】感興趣的對象,也就是e,都要繼承微軟的EventArgs
    //本例中訂閱者【也稱觀察者】MrMing,MrZhang他們感興趣的e對象,就是雜誌【magazine】
    public class PubEventArgs : EventArgs
    {
        public readonly string magazineName;
        public PubEventArgs()
        {
 
        }
        public PubEventArgs (string magazineName)
        {
           this.magazineName = magazineName;
        }
    }

    //發佈者(Publiser)
    public class Publisher
    {
        //聲明一個出版的委託
        //這裏多了一個參數sender,它所表明的就是Subject,也就是監視對象,本例中就是Publisher
        public delegate void PublishEventHander(object sender ,PubEventArgs e);
        //在委託的機制下咱們創建以個出版事件
        public event PublishEventHander Publish;

        //聲明一個可重寫的OnPublish的保護函數
        protected virtual void OnPublish(PubEventArgs e)
        {
            if (Publish != null)
            {
                //Sender = this,也就是Publisher
                this.Publish(this, e);
            }
        }

        //事件必需要在方法裏去觸發
        public void issue(string magazineName)
        {
            OnPublish(new PubEventArgs(magazineName));
        }
    }

    //Subscriber 訂閱者
    public class MrMing
    {
        //對事件感興趣的事情
        public static void Receive(object sender,PubEventArgs e)
        {
            Console.WriteLine("嘎嘎,我已經收到最新一期的《"+e.magazineName+"》啦!!");
        }
    }

    public class MrZhang
    {
        //對事件感興趣的事情
        public static void Receive(object sender, PubEventArgs e)
        {
            Console.WriteLine("幼稚,這麼大了,還看《火影忍者》,SB小明!");
            Console.WriteLine("這個我定的《"+e.magazineName+"》,哇哈哈!");
        }
    }

    class Story
    {
        public static void Main(string[] args)
        {
            //實例化一個出版社
            Publisher publisher = new Publisher();

            Console.Write("請輸入要發行的雜誌:");
            string name = Console.ReadLine();

            if (name == "火影忍者")
            {
                //給這個出火影忍者的事件註冊感興趣的訂閱者,此例中是小明
                publisher.Publish += new Publisher.PublishEventHander(MrMing.Receive);
                //發佈者在這裏觸發出版火影忍者的事件
                publisher.issue("火影忍者");
            }
            else
            {
                //給這個出火影忍者的事件註冊感興趣的訂閱者,此例中是小明[另外一種事件註冊方式]
                publisher.Publish += MrZhang.Receive;
                publisher.issue("環球日報");
            }
            Console.ReadKey();
        }
    }
複製代碼

 

輸入火影忍者後,觸發小明訂閱的事件server

顯示

經過例子我再作一次說明,其實咱們不用把Sender,e想的過於可怕

1、委託聲明原型中的Object類型的參數表明了Subject,也就是監視對象,在本例中是 Publisher(出版社)。。 
2、EventArgs 對象包含了Observer所感興趣的數據,在本例中是雜誌。

 

 

 你們先休息休息,讓大腦放鬆放鬆,先讓咱們看句名人名言:

 不少事情就像看A片,看的人以爲很爽,作的人未必!

 「中國人的勵志和國外的勵志存在很是大的不一樣,中國的勵志比較鼓勵人立下大志願,臥薪嚐膽,有朝一日成富成貴。而國外的勵志比較鼓勵人勇敢面對現實生活,面對普通人的困境,雖然結果也是成富成貴,但起點不同,相對來講,我以爲後者在操做上更現實,而前者則須要用999個失敗者來堆砌一個成功者的故事。」

 

好了,咱們接着講咱們的委託與事件,其實若是你們對設計模式精通的話,其實他們關聯的是觀察者(Observer)模式,這裏我就再也不描述什麼是觀察者模式了,只是簡單講一下他們的關聯:

在C#的event中,委託充當了抽象的Observer接口,而提供事件的對象充當了目標對象。委託是比抽象Observer接口更爲鬆耦合的設計。

若是看不懂的話也不要緊,當你們OO達到必定程度了,天然而然就會明白。

 

最後咱們來看一個咱們平常最最經常使用的觀察者模式:

場景:當咱們用信用卡刷完錢的時候,咱們就會接收到手機短信,或者是電子郵件,其實這就是Observer pattern

 

複製代碼
代碼
    //---本例場景爲當用戶從銀行帳號裏取出錢後,立刻通知電子郵件和發手機短信---
    //本例中的訂閱者,也就是觀察者是電子郵件與手機
    //發佈者,也就是被監視對象是銀行帳號


    //Obverser電子郵件,手機關心的對象e ,分別是郵件地址、手機號碼、取款金額
    public class UserEventArgs : EventArgs
    {
        public readonly string emailAddress;
        public readonly string mobilePhone;
        public readonly string amount;
        public UserEventArgs(string emailAddress, string mobilePhone,string amount)
        {
            this.emailAddress = emailAddress;
            this.mobilePhone = mobilePhone;
            this.amount = amount;
        }
    }

    //發佈者,也就是被監視的對象-銀行帳號
    class BankAccount
    {
        //聲明一個處理銀行交易的委託
        public delegate void ProcessTranEventHandler(object sender, UserEventArgs e);
        //聲明一個事件
        public event ProcessTranEventHandler ProcessTran;

        protected virtual void OnProcessTran(UserEventArgs e)
        {
            if (ProcessTran != null)
            {
                ProcessTran(this, e);
            }
        }

        public void Prcess(UserEventArgs e)
        {
            OnProcessTran(e);
        }
    }

    //觀察者Email
    class Email
    {
        public static void SendEmail(object sender, UserEventArgs e)
        {
            Console.WriteLine("向用戶郵箱" + e.emailAddress + "發送郵件:您在"+System.DateTime.Now.ToString()+"取款金額爲"+e.amount);
        }
    }

    //觀察者手機
    class Mobile
    {
        public static void SendNotification(object sender, UserEventArgs e)
        {
            Console.WriteLine("向用戶手機" + e.mobilePhone + "發送短信:您在" + System.DateTime.Now.ToString() + "取款金額爲" + e.amount);
        }
    }

    //訂閱系統,實現銀行系統訂閱幾個Observer,實現與客戶端的鬆耦合
    class SubscribSystem
    {
        public SubscribSystem()
        {
 
        }

        public SubscribSystem(BankAccount bankAccount, UserEventArgs e)
        {
            //如今咱們在銀行帳戶訂閱2個,分別是電子郵件和手機短信
            bankAccount.ProcessTran += new BankAccount.ProcessTranEventHandler(Email.SendEmail);
            bankAccount.ProcessTran += new BankAccount.ProcessTranEventHandler(Mobile.SendNotification);
            bankAccount.Prcess(e);
        }
    }

    class Client
    {
        public static void Main(string[] args)
        {
            Console.Write("請輸入您要取款的金額:");
            string amount = Console.ReadLine();
            Console.WriteLine("交易成功,請取磁卡。");
            //初始化e
            UserEventArgs user = new UserEventArgs("jinjiangbo2008@163.com", "18868789776",amount);
            //初始化訂閱系統
            SubscribSystem subject = new SubscribSystem(new BankAccount(), user);
            Console.ReadKey();
        }
    }
複製代碼

 

 

 控制檯

 

網上還有個熱水器燒水的OBSERVER PATTERN 也是蠻經典的,你們能夠看看。

相關文章
相關標籤/搜索