2017-05-05 74 views

回答

3

而不是使用委託,訂戶可以實現一個接口ISubscriber,它具有方法SomeEvent,並將其自身傳遞給發佈者(具有簽名Subscribe(ISubscriber subscriber)的方法)。然後發佈者將此參考存儲到訂閱者,並在必要時致電subscriber.SomeEvent

喜歡的東西:

public interface ISubscriber 
{ 
    void SomeEvent(object publisher, object data); 
} 

public class SomePublisher 
{ 
    private readonly HashSet<ISubscriber> subscribers = new HashSet<ISubscriber>(); 

    public void Subscribe(ISubscriber subscriber) 
    { 
     subscribers.Add(subscriber); 
    } 

    public void Unsubscribe(ISubscriber subscriber) 
    { 
     subscribers.Remove(subscriber); 
    } 

    public void DoSomething() 
    { 
     // Do something 

     // Then 

     foreach (var subscriber in subscribers) 
     { 
      object data = "Some data"; 
      subscriber.SomeEvent(this, data); 
     } 
    } 
} 

需要注意的是發佈/訂閱的這種模式並不侷限於單一的「事件」:ISubscriber可以有相應的多個「事件」多種方法。唯一的問題是,如果接口中有多個「事件」,訂閱者必須「訂閱」所有事件(必須具有所有事件的方法)。因此,如果有在ISubscriber是一個OnAddedOnRemoved方法,實現ISubscriber類都必須有兩種方法(顯然,他們可能是空的存根什麼都不做)

我要補充的是,在結束時,學員可以「模擬「通過單一方法的接口,事件可以被認爲是List<somedelegatetype>,所以事件可以被認爲是List<ISomeInterface>。 Java的,例如沒有代表和使用接口與代替他們的一個方法(例如,見Java Delegates?

+0

謝謝@ xanatos此示例非常有用,我一直在尋找 –

0

發佈/訂閱的最簡單的實現:

// Universal interface for all subscribers: 
public interface ISubscriber<TEvent> 
{ 
    void HandleEvent(object sender, TEvent ev); 
} 

// Universal publisher, can be used directly with generic argument 
public class Publisher<TEvent> 
{ 
    protected ISet<ISubscriber<TEvent>> _subscribers = new HashSet<ISubscriber<TEvent>>(); 

    public void Publish(TEvent ev) 
    { 
     foreach (var sub in _subscribers) 
     { 
      sub.HandleEvent(this, ev); 
     } 
    } 

    public void Subscribe(ISubscriber<TEvent> subscriber) 
    { 
     _subscribers.Add(subscriber); 
    } 

    public void Unsubscribe(ISubscriber<TEvent> subscriber) 
    { 
     _subscribers.Remove(subscriber); 
    } 
} 

// Or can be inherited to encapsulate any sort of logic 
public class RandomIntegerPublisher : Publisher<int> 
{ 
    private readonly Random _random = new Random(); 

    public void Publish() 
    { 
     Publish(_random.Next()); 
    } 
} 

// Example subscriber, which can even implement multiple ISubscriber interfaces 
public class ExampleSubscriber : ISubscriber<int>, ISubscriber<string> 
{ 
    public void HandleEvent(object sender, int ev) 
    { 
     Console.WriteLine($"Integer event: {ev}"); 
    } 

    public void HandleEvent(object sender, string ev) 
    { 
     Console.WriteLine($"String event: {ev}"); 
    } 
} 

void Main() 
{ 
    var subscriber = new ExampleSubscriber(); 

    var randomIntegerPublisher = new RandomIntegerPublisher(); 
    randomIntegerPublisher.Subscribe(subscriber); 

    var stringPublisher = new Publisher<string>(); 
    stringPublisher.Subscribe(subscriber); 

    randomIntegerPublisher.Publish(); 
    randomIntegerPublisher.Publish(); 
    randomIntegerPublisher.Publish(); 
    stringPublisher.Publish("Hello World!"); 
} 

輸出:

Integer event: 1547238746 
Integer event: 844169413 
Integer event: 673377792 
String event: Hello World! 

它不是很靈活,因爲使用面向發佈者/訂閱者模式實現的OOP和爲每種類型的發佈者和每個特定訂閱者創建所需的類,但它顯示了主要思想,可以通過改進你自己在很多方面。

+0

感謝Yeldar爲您提供的解決方案,它確實有幫助。我沒有足夠的積分來解決您的解決方案 –