设计一个发布和订阅服务(回调与接口)

本文关键字:服务 回调 接口 一个 | 更新日期: 2023-09-27 18:04:38

假设我需要一个发布数据的服务类,订阅者可以订阅感兴趣的数据。

我应该如何设计界面?传递回调是糟糕的设计吗?对我来说感觉不太好

选项1

public int Subscribe(string code, DataUpdatedDelegate callback) 
{
    this.subscribers[subscriptionId] = callback;
    this.codeSubscribers[code].Add(subscriptionId);
    ... 
    return subscriptionId;
}
public void UnSubscribe(int subscriptionId) 
{
    foreach list in codeSubscribers
        remove subscriptionId
    subscribers.remove(subscriptionId)
}
private void OnDataUpdated(int code, Data data)
{
     List<int> interestedSubscribers = codeSubscribers[code];
     foreach (int subId in interestedSubscribers)
     {
         DataUpdatedDelegate callback = this.subscribers[subId];
         callback(data);
     }
}

选项2

public interface ISubscriber
{
    void ProcessData(Data data);
}
public int Register(ISubscriber subscriber)
{
    return subscriptionId;
}
public void Subscribe(string code, int subscriptionId) 
{
}
... rest similar to option 1

设计一个发布和订阅服务(回调与接口)

这是一个典型的观察者模式,我肯定会选择选项2。使用界面可以提供更多选择。如果稍后需要向接口添加更多方法,则不需要更改太多代码。

我将使用委托,提供更多自由的消息有效负载,只有方法订阅而不是对象,并且不会混淆扩展/接口/mixins等。它们相当于Python中使用的pypubsub (http://pypubsub.sourceforge.net),效果非常好。

理论上,接口一旦发布到外部环境中就不应该改变。如果你决定使用一个,请记住这一点。

当然,委派的签名也是如此。此外,您总是可以提供方法重载和多个委托重载(例如,考虑Action, Action<T1,>等等)。

两种技术都有各自的优缺点;两者都不是灵丹妙药。可测试性可能会引导您使用基于接口的方法。如果有接口可以使用,模拟回调可能会容易得多。不过,使用委托也一样简单。但是,如果您使用的是mock框架或依赖注入,那么接口可能是最好的选择。