C#事件(event)的理解

一、多播委託的應用--觀察者模式

遇到一個開發的問題?
面試者:以面向對象的思想實現一下的場景:
貓:Miao一聲,緊接着引發了一系列的行爲~
Miao:引發了一系列的動作;

從代碼層面來說:代碼這樣寫好嗎?

  1. 貓職責不單一(貓就是貓,他的行爲只有Miao一聲)
  2. 依賴太重,依賴了很多的普通類; 被依賴的類如果修改,可能會引發這個貓也要修改;---代碼不穩定;
  3. 如果要控制順序---也要修改代碼; 有新需求,必須要修改歷史代碼---開閉原則;

從傳統的方式去考慮的話,我們可能會寫出來這個如此這樣的代碼

class Dog
{
    public void Bark()
    {
        Console.WriteLine("Dog Bark!");

    }
}

class Fox
{
    public void Eat()
    {
        Console.WriteLine("Fox Eat!");

    }
    
}

class Cat
{
    public void Miao()
    {
        new Fox().Eat();
        new Dog().Bark();

        Console.WriteLine("Cat Miao!");
    }
}

從代碼層面來說:代碼這樣寫好嗎?

  1. 貓職責不單一(貓就是貓,他的行爲只有Miao一聲)
  2. 依賴太重,依賴了很多的普通類; 被依賴的類如果修改,可能會引發這個貓也要修改;---代碼不穩定;
  3. 如果要控制順序---也要修改代碼; 有新需求,必須要修改歷史代碼---開閉原則;

如何解決呢? 第一個問題:讓貓的職責單一, 後續觸發的行爲,貓Miao一聲之後,只負責觸發; 觸發的是一堆的行爲;
請問:如果要希望在觸發一個行爲後,能夠執行多個行爲,執行一系列的行爲?? 怎麼辦?-------多播委託;

核心:把依賴的東西轉移到上端,保證當前類的穩定; ----可以做到解耦
二者實現本質:是相通的; 都是類似於一個盒子, OOP: 盒子中裝對象 委託:盒子裝方法;

通過OOP 繼承實現的ObServer
IObject.cs

 public interface IObject
 {
     public void DoAction();

 }

Baby.cs

public class Baby:IObject
{
   public void Cry()
    {
        Console.WriteLine("Baby Cry");
    }

    public void DoAction()
    {
        Cry();
    }
}

Brother.cs

 public class Brother:IObject
 {
     public void Turn()
     {
         Console.WriteLine("Brother Turn");
     }

     public void DoAction()
     {
         Turn();
     }
 }

Dog.cs

 public class Dog:IObject
 {
     public void Wang()
     {
         Console.WriteLine("Dog Wang");
     }

     public void DoAction()
     {
         Wang();
     }
 }

Father.cs

 public class Father:IObject
 {
     public void Roar()
     {
         Console.WriteLine("Father Roar");
     }

     public void DoAction()
     {
         Roar();
     }
 }

Mother.cs

 public class Mother:IObject
 {
     public void Wispher()
     {
         Console.WriteLine("Mother Wispher");
     }

     public void DoAction()
     {
         Wispher();
     }
 }

Mouse.cs

 public class Mouse:IObject
 {
     public void Run()
     {
         Console.WriteLine("Mouse Run");
     }
     public void DoAction()
     {
         Run();
     }
 }

Neighbor.cs

public class Neighbor:IObject
{
    public void Awake()
    {
        Console.WriteLine("Neighbor Awake");
    }
    public void DoAction()
    {
        Awake();
    }

}

Stealer.cs

public class Stealer:IObject
{
    public void Hide()
    {
        Console.WriteLine("Stealer Hide");
    }
    public void DoAction()
    {
        Hide();
    }
}

Cat.cs

public class Cat
{  
    public List<IObject> ObserList=new List<IObject>(); 
    public void MiaoObserver()
    {
        Console.WriteLine($"{this.GetType().Name} MiaoObserver========");
        foreach ( IObject item in ObserList )
        { 
            item.DoAction();
        } 
    }
}

Progarm.cs

Console.WriteLine("=========================================");
Console.WriteLine("=========================================");
{
    Cat cat = new Cat();
    cat.objects.Add(new Baby());
    cat.objects.Add(new Mother());
    cat.objects.Add(new Dog());
    cat.objects.Add(new Mouse());
    cat.objects.Add(new Father());
    cat.objects.Add(new Neighbor());
    cat.objects.Add(new Stealer());
    cat.objects.Add(new Brother());
    cat.MiaoObserver();
}
Console.WriteLine("=========================================");
Console.WriteLine("=========================================");

通過委託實現
cat.cs

public Action? MiaoDelegate;

public void MiaoDelegateObserver()
{
    Console.WriteLine($"{this.GetType().Name} MiaoDelegateObserver========");
    if (MiaoDelegate != null)
    {
        MiaoDelegate();
    }
}

program.cs

Console.WriteLine("=========================================");
Console.WriteLine("=========================================");
{
    Cat cat = new Cat();
    cat.MiaoDelegate += new Baby().Cry;
    cat.MiaoDelegate += new Mother().Wispher;
    cat.MiaoDelegate += new Dog().Wang;
    cat.MiaoDelegate += new Mouse().Run;
    cat.MiaoDelegate += new Father().Roar;
    cat.MiaoDelegate += new Neighbor().Awake;
    cat.MiaoDelegate += new Stealer().Hide;
    cat.MiaoDelegate += new Brother().Turn;
    //cat.ActionHander -= new Baby().Cry;
    //  cat.ActionHander.Invoke();// 委託可以在定義委託所在類的外部去執行;
    cat.MiaoDelegateObserver();
}

Console.WriteLine("=========================================");
Console.WriteLine("=========================================");

通過事件實現

cat.cs

public event Action ActionHanderEvent;   
public void MiaoEvent()
{
    Console.WriteLine($"{this.GetType().Name} MiaoEvent========");
    ActionHanderEvent.Invoke();   //這個行爲要一定是執行 MiaoEvent方法的時候才觸發的;
} 

program.cs

 Console.WriteLine("事件的應用:============================");
 {
     Cat cat = new Cat();
     cat.ActionHanderEvent += new Baby().Cry;
     cat.ActionHanderEvent += new Mother().Wispher;
     cat.ActionHanderEvent += new Dog().Wang;
     cat.ActionHanderEvent += new Mouse().Run;
     cat.ActionHanderEvent += new Father().Roar;
     cat.ActionHanderEvent += new Neighbor().Awake;
     cat.ActionHanderEvent += new Stealer().Hide; 
     // cat.ActionHanderEvent -= new Baby().Cry;
     //cat.ActionHanderEvent.Invoke();
     cat.MiaoEvent ();
 }

什麼是事件,其實就是委託的實例+關鍵字; 事件是一個特殊的委託;
委託和事件有什麼區別?
1 多個了關鍵字
2 事件的權限控制會更加嚴格--事件的執行,只能,必須在聲明這個事件所在的類的內部才能執行;
已經有了委託,爲什麼還要事件呢?----在系統框架設計中,需要這樣的權限控制;

已經有了委託,爲什麼還要事件呢?----在系統框架設計中,需要這樣的權限控制;
使用winform程序來做示範

登錄
思路:按鈕點擊會觸發這個方法,如果是通過事件來完成,必然會有一個地方定義得有事件,還要把這個方法給註冊到事件中去;
執行的邏輯:在按鈕初始化的時候,把按鈕中的Click 指向一個方法btnLogin_Click;
運行起來: 鼠標點擊按鈕----操作系統可以捕捉到鼠標的信號,通過句柄判斷,確定是哪個程序,通過程序中句柄判斷是按個一個組件(按鈕),可以獲取到按鈕的實例; 得到的是登錄按鈕; 鼠標單機左鍵信號,按鈕

委託和事件的功能差不多---按鈕的點擊後觸發的行爲,爲什麼用事件而不用委託?????
就是爲了要管控這個按鈕,只能在特定的情況下去執行;

如果用委託:委託就可以在外部去執行;
點擊登錄,觸發登錄的方法----必須是點擊登錄後觸發 所以只能用事件而不能用委託
點擊註冊,觸發註冊的方法----必須是點擊註冊後觸發 所以只能用事件而不能用委託
不能通過任何其他別的渠道來觸發這個方法
如果我使用委託:儘管一在點擊了按鈕之後,可以觸發對應的行爲,但是委託沒有權限的限制,就可以在外部執行這個委託----不允許的;保證動作觸發的來源一定是來自於哪裏;

委託和事件的相通性:
二者功能差不多,觀察者;在程序中,除了保證代碼的問題;
其他場景
三個按鈕---鼠標指向---變顏色(按鈕的行爲); 所有的按鈕都有這個行爲; 而單單隻有登錄和註冊--點擊後可以觸發對應的方法;因爲給這兩個按鈕的Click事件註冊了行爲;

在系統的框架中,如果有一段邏輯的執行; 其中有一些通用的邏輯(三個按鈕都有執向變顏色),還有一些個性化的邏輯,每個按鈕點擊後可能需要執行不同的邏輯; 可以通過事件來進行註冊;

價值: 可以把通用的邏輯封裝
把可變的邏輯通過事件註冊

執行來了,通用邏輯(統一的代碼執行)-----可變的邏輯(各自執行各自的~·) 程序可以更加靈活~~ Web--- ASP.NET MVC管道處理模型~~

2.定義事件+實現發佈訂閱

1.朝夕要發佈新課程,嵌入式和C++ Qt (都是Richard老師給大家上課)
2.很多小夥伴們很期待,很關注
3.如果課程發佈,根據需求報名學習

 public class EventStandard
 { 
     private static PublicCourse publicCourse1 = new PublicCourse()
     {
         Id = 222,
         Name = "Qt和C++",
     }; 
     private static PublicCourse publicCourse2 = new PublicCourse()
     {
         Id = 222,
         Name = "嵌入式開發",
     };
      
     /// <summary>
     /// 發佈課程
     /// </summary>
     public static void Show()
     {
         publicCourse1.PublicShow();// 只關注發佈,發佈後,會有後續的行爲
         publicCourse2.PublicShow();
     }

     /// <summary>
     /// 初始化訂閱者和發佈者之間的關係( 訂閱中心 )
     /// </summary>
     public static void Init()
     {
         StudentUser user1 = new StudentUser()
         {
             Id = 123,
             Name = "夕林吹雪"
         };
         publicCourse1.Publish += user1.Buy;
         publicCourse2.Publish += user1.Buy;
      
         StudentUser user2 = new StudentUser()
         {
             Id = 123,
             Name = "張三"
         };
         publicCourse1.Publish += user2.Buy;
         publicCourse2.Publish += user2.Buy;


         StudentUser user3 = new StudentUser()
         {
             Id = 123,
             Name = "李四"
         };
         publicCourse1.Publish += user3.Buy;
         publicCourse2.Publish += user3.Buy;
     }

 }

 /// <summary>
 /// 發佈者
 /// 發佈後,就會有後續的邏輯---具體是什麼,不知道
 /// </summary>
 public class PublicCourse
 {
     public int Id { get; set; }

     public string Name { get; set; }

     public void PublicShow()
     {
         Console.WriteLine("朝夕新課程發佈: Qt+C++  嵌入式開發~~~");
         //會有很多的人關注
         //會有很多的後續動作執行, 有人諮詢,有人報名,有人體驗課程~

         Publish.Invoke(this, new CourseInfo()
         {
             Id=345,
             Title="Qt和 C++"
         });

     }
     public event EventHandler Publish;
 }


 /// <summary>
 /// 訂閱者(訂戶):
 /// 訂閱消息,消息出現,就會觸發行爲;
 /// </summary>
 public class StudentUser
 {
     public int Id { get; set; }
     public string Name { get; set; }

     public void Buy(object? sender, EventArgs e)
     {
         PublicCourse  course= (PublicCourse)(sender);
         Console.WriteLine($"朝夕有新的課程發佈,可稱爲{course.Name}");
         Console.WriteLine($"用戶:{Name}先了解下,考慮考慮");
         Console.WriteLine($"可以購買學習~~");
     }

 }

 /// <summary>
 /// 擴展參數
 /// </summary>
 public class CourseInfo : EventArgs
 {
     public int Id { get; set; }
     public string Title { get; set; }
     public string Description { get; set; }
     public string TeacherWechatNum { get; set; }
 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章