前言
今天講一下事件驅動,這個不是領域驅動設計里的事件源(Event Source), 這個以后再講,今天主要講一下如何用事件來解耦,主要的原因是我們有個項目有個功能我覺得用事件的方式比較好,正好寫篇博客,就不用專門給他們講了。
解耦
說到解耦,我們很熟悉分層設計,比如上層依賴於抽象,不依賴於具體的實現。比如一個類使用另一個類,我們使用接口而不直接使用實現類。
public EquipmentService(IEmailService emailService, IEquipmentRepository equipmentRepository)
{
_emailService = emailService;
_equipmentRepository = equipmentRepository;
}
為何用事件?
SRP (單一職責)
比如我們一個會議室預定系統,我們的一個設備壞了。我們需要通知預定這個會議室的所有人。於是我們需要發郵件。
偽代碼如下
public class EquipmentService
{
private readonly IEmailService _emailService;
private readonly IEquipmentRepository _equipmentRepository;
public EquipmentService(IEmailService emailService, IEquipmentRepository equipmentRepository)
{
_emailService = emailService;
_equipmentRepository = equipmentRepository;
}
public void SetEquipmentBroken(string Id)
{
var equipment = _equipmentRepository.GetById(Id);
equipment.DeActive();
_emailService.SendEmail();
}
}
但是,問題來了,如果后來我們要說,如果設備壞了,我們要更改可用庫存的數量,這時候我們是不是要在這里修改代碼而引入IInventoryService? 后來如果經理說設備壞了你們盡然不告訴我,你們要鬧哪樣?這個時候我們是不是要修改代碼引入ISMSService.Info(Manager)? 即使我們不考慮OCP原則,不考慮單一職責,我們程序員也會哭,我就DeActive一個設備,你要我做這么多事,我哪里清楚所有的功能?我就罵過程序員,你做這個功能呢為什么沒考慮全!!!漏掉了這么重要的功能。
而問題,程序員從來沒考慮全過,因此我就想辦法如何解決這個程序員不仔細的問題。
事件驅動
因為我熟悉iOS的開發,我就想到了iOS的Notification Center. 那我我DeActive一個設備,我就只DeActive這個設備,很SRP是不是? 但是別的地方如何拿到通知? 於是事件就自然的付出水面了。如果設備被DeActive了,程序就只需要喊一聲,老子把設備DeActive了,你們要鬧哪樣你們自己看着辦,代碼如下。
public void SetEquipmentBroken(string Id)
{
var equipment = _equipmentRepository.GetById(Id);
equipment.DeActive();
EventBus.Publish(new EquipmentDeActivedEvent {Id = equipment.Id});
}
這樣,通知會議室預定者的模塊去通知,給老板發短信的模塊就通知老板就OK了。
總結
這里我們先將事件驅動,下一篇展示如何實現同步的事件,以后轉換為異步那也很容易,讓多個接受者處理這個事件,接受者可以是動態的哦,以后老板娘也想知道的話,代碼也不用改的親,好,我先去寫實現代碼去!