什么是Pub-Sub
發布訂閱是一種設計模式,它允許應用程式組件之間進行松散耦合,
其實訂閱發布設計中主要是發布者生成事件通道,用于在不了解任何訂閱者存在的情況下通知訂閱者,
當然委托EventHandlers和Event關鍵字在此事件處理機制中擔任著重要的角色,下面我們來看看如何使用它們,
Pub和Sub的使用
首先我們看一個簡單地訂閱發布模式.
定義一個Action委托,無回傳值.
namespace PubSubPattern
{
public class Pub
{
public Action OnChange { get; set; }
public void Raise()
{
if (OnChange != null)
{
//Invoke OnChange Action
OnChange();
}
}
}
class Program
{
static void Main(string[] args)
{
var p = new Pub();
p.OnChange += () => Console.WriteLine("Sub 1");
p.OnChange += () => Console.WriteLine("Sub 2");
p.Raise();
Console.WriteLine("Press enter !");
Console.ReadLine();
}
}
}
如上代碼我們創建了一個發布者,并且我們呼叫委托進行創建我們匿名方法來訂閱,由于委托提供了多播功能,因此我們可以OnChange屬性上使用+=.
雖然說我們看著如上代碼執行無誤,但是程式中仍然存在一些問題,如果使用=而不是+=,那么OnChange屬性中將會洗掉第一個訂閱者,
由于OnChange是公共屬性,因此該類的任何外部用戶都可以進行呼叫p.OnChange().
使用Event關鍵字的發布訂閱
下面我們來看看使用event關鍵字后的代碼
public class Pub
{
public event Action OnChange = delegate { };
public void Raise()
{
OnChange();
}
}
class Program
{
static void Main(string[] args)
{
Pub p = new Pub();
p.OnChange += () => Console.WriteLine("Sub 1");
p.OnChange += () => Console.WriteLine("Sub 2");
p.Raise();
Console.WriteLine("Press enter !");
Console.ReadLine();
}
}
通過如上代碼我們試著去解決我們第一處所說的問題,我們會發現使用event關鍵字后可以保護我們OnChange免受不必要的訪問,它不允許使用=也就是說他不允許直接進行分配委托,因此我們現在可以避免使用=,從而避免應用程式不必要的麻煩,
可能大家也會發現OnChange初始化為空委托delegate{},這樣可以確保我們的OnChange永遠不會為空,因為當我們其他進行對他呼叫的時候我們可以在代碼中進行洗掉對他的非空檢查.
使用EventHandlers的發布訂閱
其實在訂閱發布中,發布者和訂閱者都不知道彼此的存在,有個EventHandler,它被稱為訊息代理或者說事件總線,發布者和訂閱者都應該知道它,它接收所有傳入的訊息并且將它們進行轉發.
因此呢,在如下片段中我們使用EventHandler而不是用Action.
public delegate void EventHandler(
object sender,
EventArgs e
)
默認情況下,EventHandler將發送物件和一些事件引數作為引數,
public class MyEventArgs : EventArgs
{
public int Value { get; set; }
public MyEventArgs(int value)
{
Value = https://www.cnblogs.com/yyfh/p/value;
}
}
public class Pub
{
public event EventHandler OnChange = delegate { };
public void Raise()
{
OnChange(this, new MyEventArgs(1));
}
}
class Program
{
static void Main(string[] args)
{
Pub p = new Pub();
p.OnChange += (sender, e) => Console.WriteLine("Sub 1.Value:" + e.Value);
p.OnChange += (sender, e) => Console.WriteLine("Sub 2.Value:" + e.Value);
p.Raise();
Console.WriteLine("Press enter !");
Console.ReadLine();
}
}
如上代碼中通過pub類使用通用的EventHandler,它觸發EventHandler OnChange時需要傳遞的事件引數型別,在上面代碼片段中為MyArgs
事件中的例外
我們繼續說一種情況.大家看如下代碼片段
public class MyEventArgs : EventArgs
{
public int Value { get; set; }
public MyEventArgs(int value)
{
Value = https://www.cnblogs.com/yyfh/p/value;
}
}
public class Pub
{
public event EventHandler OnChange = delegate { };
public void Raise()
{
OnChange(this, new MyEventArgs(1));
}
}
class Program
{
static void Main(string[] args)
{
Pub p = new Pub();
p.OnChange += (sender, e) => Console.WriteLine("Sub 1.Value:" + e.Value);
p.OnChange += (sender, e) => { throw new Exception(); };
p.OnChange += (sender, e) => Console.WriteLine("Sub 2.Value:" + e.Value);
p.Raise();
Console.WriteLine("Press enter !");
Console.ReadLine();
}
}
運行如上代碼后,大家會發現第一個訂閱者已經執行成功了,第二個訂閱者引發了例外,而第三個訂閱者未被呼叫.這是一個很尷尬的事情.
如果說我們覺得如上的程序不是我們預期的,我們需要手動引發事件并處理例外,這時候我們可以使用Delegate基類中定義的GetInvoctionList來幫助我們實作這些,
我們繼續看如下代碼
public class MyEventArgs : EventArgs
{
public int Value { get; set; }
public MyEventArgs(int value)
{
Value = https://www.cnblogs.com/yyfh/p/value;
}
}
public class Pub
{
public event EventHandler OnChange = delegate { };
public void Raise()
{
MyEventArgs eventArgs = new MyEventArgs(1);
List exceptions = new List();
foreach (Delegate handler in OnChange.GetInvocationList())
{
try
{
handler.DynamicInvoke(this, eventArgs);
}
catch (Exception e)
{
exceptions.Add(e);
}
}
if (exceptions.Any())
{
throw new AggregateException(exceptions);
}
}
}
class Program
{
static void Main(string[] args)
{
Pub p = new Pub();
p.OnChange += (sender, e) => Console.WriteLine("Sub 1.Value:" + e.Value);
p.OnChange += (sender, e) => { throw new Exception(); };
p.OnChange += (sender, e) => Console.WriteLine("Sub 2.Value:" + e.Value);
p.Raise();
Console.WriteLine("Press enter !");
Console.ReadLine();
}
}
Reference
https://github.com/hueifeng/DesignPatterns-Samples/tree/master/PubSubPattern
https://hackernoon.com/observer-vs-pub-sub-pattern-50d3b27f838c
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/33182.html
標籤:C#
