Background: sto sviluppando un framework di messaggistica. Questo framework consentirà:
- invio di messaggi su un bus di servizio
- abbonarsi alle code sul bus dei messaggi
- abbonarsi agli argomenti su un bus dei messaggi
Attualmente stiamo usando RabbitMQ, ma so che ci sposteremo su Microsoft Service Bus (in Premessa) nel prossimo futuro.
Ho intenzione di creare un insieme di interfacce e implementazioni in modo tale che quando ci spostiamo su ServiceBus, ho semplicemente bisogno di fornire una nuova implementazione senza modificare alcun codice client (ad esempio editori o abbonati).
Il problema qui è che RabbitMQ e ServiceBus non sono direttamente traducibili. Ad esempio, RabbitMQ si basa su scambi e nomi di argomenti, mentre ServiceBus si basa su Namespace e Code. Inoltre, non ci sono interfacce comuni tra il client ServiceBus e il client RabbitMQ (ad esempio, entrambi possono avere un IConnection, ma l'interfaccia è diversa - non da uno spazio dei nomi comune).
Quindi, a mio avviso, posso creare un'interfaccia come segue:
public interface IMessageReceiver{
void AddSubscription(ISubscription subscriptionDetails)
}
A causa delle proprietà non traducibili delle due tecnologie, le implementazioni di ServiceBus e RabbitMQ dell'interfaccia precedente hanno requisiti diversi. Quindi la mia implementazione di IMessageReceiver su RabbitMq potrebbe essere simile a questa:
public void AddSubscription(ISubscription subscriptionDetails){
if(!subscriptionDetails is RabbitMqSubscriptionDetails){
// I have a problem!
}
}
Per me, la riga precedente infrange la regola di sostituibilità di Liskov.
Ho pensato di capovolgerlo, in modo che una sottoscrizione accetti un IMessageConnection, ma ancora una volta RabbitMq Subscription richiederebbe proprietà specifiche di un RabbitMQMessageConnection.
Quindi, le mie domande sono:
- Ho corretto che ciò interrompe LSP?
- Siamo d'accordo che in alcuni casi è inevitabile, o, mi manca qualcosa?
Si spera che questo sia chiaro e in tema!