背景:我正在开发一个消息传递框架。该框架将允许:
- 通过服务总线发送消息
- 订阅消息总线上的队列
- 订阅消息总线上的主题
我们目前正在使用RabbitMQ,但我知道我们将在不久的将来迁移到Microsoft Service Bus(在Premise上)。
我计划创建一组接口和实现,以便当我们转向ServiceBus时,我只需要提供一个新的实现而无需修改任何客户端代码(即发布者或订阅者)。
这里的问题是RabbitMQ和ServiceBus不能直接翻译。例如,RabbitMQ依赖于交换和主题名称,而ServiceBus全部与命名空间和队列有关。同样,在ServiceBus客户端和RabbitMQ客户端之间没有公共接口(例如,两者都可以具有IConnection,但是接口是不同的-不同于公共名称空间)。
因此,就我而言,我可以创建如下界面:
public interface IMessageReceiver{
void AddSubscription(ISubscription subscriptionDetails)
}
由于这两种技术的不可翻译特性,上述接口的ServiceBus和RabbitMQ实现具有不同的要求。因此,我的IMessageReceiver的RabbitMq实现可能如下所示:
public void AddSubscription(ISubscription subscriptionDetails){
if(!subscriptionDetails is RabbitMqSubscriptionDetails){
// I have a problem!
}
}
对我来说,上面的线打破了李斯科夫的可替代性规则。
我考虑过将其翻转,以便订阅可以接受IMessageConnection,但是RabbitMq订阅再次需要RabbitMQMessageConnection的特定属性。
因此,我的问题是:
- 我是否认为这会破坏LSP?
- 我们是否同意在某些情况下这是不可避免的,还是我错过了一些东西?
希望这很清楚,而且是话题!
interface IMessageReceiver<T extends ISubscription>{void AddSubscription(T subscriptionDetails); }
。然后,实现可能看起来像public class RabbitMqMessageReceiver implements IMessageReceiver<RabbitMqSubscriptionDetails> { public void AddSubscription(RabbitMqSubscriptionDetails subscriptionDetails){} }
(在Java中)。
interface TestInterface<T extends ISubscription>
可以清楚地传达接受哪些类型,以及实现之间的差异。