Contexte: Je développe un cadre de messagerie. Ce cadre permettra:
- envoi de messages via un bus de service
- abonnement aux files d'attente sur le bus de messages
- abonnement à des sujets sur un bus de messages
Nous utilisons actuellement RabbitMQ, mais je sais que nous allons passer à Microsoft Service Bus (sur site) dans un avenir très proche.
Je prévois de créer un ensemble d'interfaces et d'implémentations de sorte que lorsque nous passerons à ServiceBus, je n'ai qu'à fournir une nouvelle implémentation sans modifier le code client (c'est-à-dire les éditeurs ou les abonnés).
Le problème ici est que RabbitMQ et ServiceBus ne sont pas directement traduisibles. Par exemple, RabbitMQ s'appuie sur les échanges et les noms de rubrique, tandis que ServiceBus concerne les espaces de noms et les files d'attente. De plus, il n'y a pas d'interfaces communes entre le client ServiceBus et le client RabbitMQ (par exemple, les deux peuvent avoir une connexion IC, mais l'interface est différente - pas d'un espace de noms commun).
Donc à mon point, je peux créer une interface comme suit:
public interface IMessageReceiver{
void AddSubscription(ISubscription subscriptionDetails)
}
En raison des propriétés non traduisibles des deux technologies, les implémentations ServiceBus et RabbitMQ de l'interface ci-dessus ont des exigences différentes. Donc, mon implémentation RabbitMq de IMessageReceiver peut ressembler à ceci:
public void AddSubscription(ISubscription subscriptionDetails){
if(!subscriptionDetails is RabbitMqSubscriptionDetails){
// I have a problem!
}
}
Pour moi, la ligne ci-dessus rompt la règle de substituabilité de Liskov.
J'ai envisagé de retourner cela, de sorte qu'un abonnement accepte un IMessageConnection, mais encore une fois, l'abonnement RabbitMq nécessiterait des propriétés spécifiques d'un RabbitMQMessageConnection.
Donc, mes questions sont:
- Suis-je correct que cela casse LSP?
- Sommes-nous d'accord pour dire que dans certains cas, c'est inévitable, ou est-ce que je manque quelque chose?
J'espère que c'est clair et sur le sujet!
interface IMessageReceiver<T extends ISubscription>{void AddSubscription(T subscriptionDetails); }
. Une implémentation pourrait alors ressembler public class RabbitMqMessageReceiver implements IMessageReceiver<RabbitMqSubscriptionDetails> { public void AddSubscription(RabbitMqSubscriptionDetails subscriptionDetails){} }
(en java).
interface TestInterface<T extends ISubscription>
cela communiquerait clairement quels types sont acceptés et qu'il existe des différences entre les implémentations.