一、多播委托的應(yīng)用--觀察者模式
遇到一個(gè)開(kāi)發(fā)的問(wèn)題?
面試者:以面向?qū)ο蟮乃枷雽?shí)現(xiàn)一下的場(chǎng)景:
貓:Miao一聲,緊接著引發(fā)了一系列的行為~
Miao:引發(fā)了一系列的動(dòng)作;
從代碼層面來(lái)說(shuō):代碼這樣寫好嗎?
- 貓職責(zé)不單一(貓就是貓,他的行為只有Miao一聲)
- 依賴太重,依賴了很多的普通類; 被依賴的類如果修改,可能會(huì)引發(fā)這個(gè)貓也要修改;---代碼不穩(wěn)定;
- 如果要控制順序---也要修改代碼; 有新需求,必須要修改歷史代碼---開(kāi)閉原則;
從傳統(tǒng)的方式去考慮的話,我們可能會(huì)寫出來(lái)這個(gè)如此這樣的代碼
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!");
}
}
從代碼層面來(lái)說(shuō):代碼這樣寫好嗎?
- 貓職責(zé)不單一(貓就是貓,他的行為只有Miao一聲)
- 依賴太重,依賴了很多的普通類; 被依賴的類如果修改,可能會(huì)引發(fā)這個(gè)貓也要修改;---代碼不穩(wěn)定;
- 如果要控制順序---也要修改代碼; 有新需求,必須要修改歷史代碼---開(kāi)閉原則;
如何解決呢? 第一個(gè)問(wèn)題:讓貓的職責(zé)單一, 后續(xù)觸發(fā)的行為,貓Miao一聲之后,只負(fù)責(zé)觸發(fā); 觸發(fā)的是一堆的行為;
請(qǐng)問(wèn):如果要希望在觸發(fā)一個(gè)行為后,能夠執(zhí)行多個(gè)行為,執(zhí)行一系列的行為?? 怎么辦?-------多播委托;
核心:把依賴的東西轉(zhuǎn)移到上端,保證當(dāng)前類的穩(wěn)定; ----可以做到解耦
二者實(shí)現(xiàn)本質(zhì):是相通的; 都是類似于一個(gè)盒子, OOP: 盒子中裝對(duì)象 委托:盒子裝方法;
通過(guò)OOP 繼承實(shí)現(xiàn)的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("=========================================");
通過(guò)委托實(shí)現(xiàn)
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();// 委托可以在定義委托所在類的外部去執(zhí)行;
cat.MiaoDelegateObserver();
}
Console.WriteLine("=========================================");
Console.WriteLine("=========================================");
通過(guò)事件實(shí)現(xiàn)
cat.cs
public event Action ActionHanderEvent;
public void MiaoEvent()
{
Console.WriteLine($"{this.GetType().Name} MiaoEvent========");
ActionHanderEvent.Invoke(); //這個(gè)行為要一定是執(zhí)行 MiaoEvent方法的時(shí)候才觸發(fā)的;
}
program.cs
Console.WriteLine("事件的應(yīng)用:============================");
{
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 ();
}
什么是事件,其實(shí)就是委托的實(shí)例+關(guān)鍵字; 事件是一個(gè)特殊的委托;
委托和事件有什么區(qū)別?
1 多個(gè)了關(guān)鍵字
2 事件的權(quán)限控制會(huì)更加嚴(yán)格--事件的執(zhí)行,只能,必須在聲明這個(gè)事件所在的類的內(nèi)部才能執(zhí)行;
已經(jīng)有了委托,為什么還要事件呢?----在系統(tǒng)框架設(shè)計(jì)中,需要這樣的權(quán)限控制;
已經(jīng)有了委托,為什么還要事件呢?----在系統(tǒng)框架設(shè)計(jì)中,需要這樣的權(quán)限控制;
使用winform程序來(lái)做示范
登錄
思路:按鈕點(diǎn)擊會(huì)觸發(fā)這個(gè)方法,如果是通過(guò)事件來(lái)完成,必然會(huì)有一個(gè)地方定義得有事件,還要把這個(gè)方法給注冊(cè)到事件中去;
執(zhí)行的邏輯:在按鈕初始化的時(shí)候,把按鈕中的Click 指向一個(gè)方法btnLogin_Click;
運(yùn)行起來(lái): 鼠標(biāo)點(diǎn)擊按鈕----操作系統(tǒng)可以捕捉到鼠標(biāo)的信號(hào),通過(guò)句柄判斷,確定是哪個(gè)程序,通過(guò)程序中句柄判斷是按個(gè)一個(gè)組件(按鈕),可以獲取到按鈕的實(shí)例; 得到的是登錄按鈕; 鼠標(biāo)單機(jī)左鍵信號(hào),按鈕
委托和事件的功能差不多---按鈕的點(diǎn)擊后觸發(fā)的行為,為什么用事件而不用委托?????
就是為了要管控這個(gè)按鈕,只能在特定的情況下去執(zhí)行;
如果用委托:委托就可以在外部去執(zhí)行;
點(diǎn)擊登錄,觸發(fā)登錄的方法----必須是點(diǎn)擊登錄后觸發(fā) 所以只能用事件而不能用委托
點(diǎn)擊注冊(cè),觸發(fā)注冊(cè)的方法----必須是點(diǎn)擊注冊(cè)后觸發(fā) 所以只能用事件而不能用委托
不能通過(guò)任何其他別的渠道來(lái)觸發(fā)這個(gè)方法
如果我使用委托:盡管一在點(diǎn)擊了按鈕之后,可以觸發(fā)對(duì)應(yīng)的行為,但是委托沒(méi)有權(quán)限的限制,就可以在外部執(zhí)行這個(gè)委托----不允許的;保證動(dòng)作觸發(fā)的來(lái)源一定是來(lái)自于哪里;
委托和事件的相通性:
二者功能差不多,觀察者;在程序中,除了保證代碼的問(wèn)題;
其他場(chǎng)景
三個(gè)按鈕---鼠標(biāo)指向---變顏色(按鈕的行為); 所有的按鈕都有這個(gè)行為; 而單單只有登錄和注冊(cè)--點(diǎn)擊后可以觸發(fā)對(duì)應(yīng)的方法;因?yàn)榻o這兩個(gè)按鈕的Click事件注冊(cè)了行為;
在系統(tǒng)的框架中,如果有一段邏輯的執(zhí)行; 其中有一些通用的邏輯(三個(gè)按鈕都有執(zhí)向變顏色),還有一些個(gè)性化的邏輯,每個(gè)按鈕點(diǎn)擊后可能需要執(zhí)行不同的邏輯; 可以通過(guò)事件來(lái)進(jìn)行注冊(cè);
價(jià)值: 可以把通用的邏輯封裝
把可變的邏輯通過(guò)事件注冊(cè)
執(zhí)行來(lái)了,通用邏輯(統(tǒng)一的代碼執(zhí)行)-----可變的邏輯(各自執(zhí)行各自的~·) 程序可以更加靈活~~ Web--- ASP.NET MVC管道處理模型~~文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-837928.html
2.定義事件+實(shí)現(xiàn)發(fā)布訂閱
1.朝夕要發(fā)布新課程,嵌入式和C++ Qt (都是Richard老師給大家上課)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-837928.html
2.很多小伙伴們很期待,很關(guān)注
3.如果課程發(fā)布,根據(jù)需求報(bào)名學(xué)習(xí)
public class EventStandard
{
private static PublicCourse publicCourse1 = new PublicCourse()
{
Id = 222,
Name = "Qt和C++",
};
private static PublicCourse publicCourse2 = new PublicCourse()
{
Id = 222,
Name = "嵌入式開(kāi)發(fā)",
};
/// <summary>
/// 發(fā)布課程
/// </summary>
public static void Show()
{
publicCourse1.PublicShow();// 只關(guān)注發(fā)布,發(fā)布后,會(huì)有后續(xù)的行為
publicCourse2.PublicShow();
}
/// <summary>
/// 初始化訂閱者和發(fā)布者之間的關(guān)系( 訂閱中心 )
/// </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>
/// 發(fā)布者
/// 發(fā)布后,就會(huì)有后續(xù)的邏輯---具體是什么,不知道
/// </summary>
public class PublicCourse
{
public int Id { get; set; }
public string Name { get; set; }
public void PublicShow()
{
Console.WriteLine("朝夕新課程發(fā)布: Qt+C++ 嵌入式開(kāi)發(fā)~~~");
//會(huì)有很多的人關(guān)注
//會(huì)有很多的后續(xù)動(dòng)作執(zhí)行, 有人咨詢,有人報(bào)名,有人體驗(yàn)課程~
Publish.Invoke(this, new CourseInfo()
{
Id=345,
Title="Qt和 C++"
});
}
public event EventHandler Publish;
}
/// <summary>
/// 訂閱者(訂戶):
/// 訂閱消息,消息出現(xiàn),就會(huì)觸發(fā)行為;
/// </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($"朝夕有新的課程發(fā)布,可稱為{course.Name}");
Console.WriteLine($"用戶:{Name}先了解下,考慮考慮");
Console.WriteLine($"可以購(gòu)買學(xué)習(xí)~~");
}
}
/// <summary>
/// 擴(kuò)展參數(shù)
/// </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; }
}
到了這里,關(guān)于C#事件(event)的理解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!