我最近在接受采访时被问到,如果我们没有活动和代表,我们如何在没有代表和活动的情况下实现Publisher和Subsriber模型的相同功能。
你能用一个例子向我解释一下它会非常有用并且也会帮助其他人吗?
答案 0 :(得分:6)
订阅者可以实现具有方法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);
}
}
}
请注意,此发布商/订阅者模式不限于单个&#34;事件&#34;:ISubscriber
可能有多个方法对应多个&#34;事件&#34;。唯一的问题是如果有多个&#34;事件&#34;在界面中,订户必须&#34;订阅&#34;所有事件(必须有所有事件的方法)。因此,如果OnAdded
中有OnRemoved
和ISubscriber
方法,那么实现ISubscriber
的类必须同时具有这两种方法(显然它们可能是无效的空存根)
我补充一点,最后,代表们可以&#34;模拟&#34;通过具有单个方法的接口,可以将事件视为List<somedelegatetype>
,因此可以将事件视为List<ISomeInterface>
。例如,Java没有委托,并使用单一方法代替接口(参见例如Java Delegates?)
答案 1 :(得分:3)
发布者/订阅者最简单的实现:
// 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用于发布者/订阅者模式实现,并且为每种类型的发布者和每个特定订阅者创建了必需的类,因此它不是非常灵活,但它显示了主要想法,可以通过多种方式自行改进。