Contesto: sto sviluppando un framework di messaggistica. Questo quadro consentirà:
- invio di messaggi tramite un bus di servizio
- iscriversi alle code sul bus dei messaggi
- sottoscrivendo argomenti su un bus messaggi
Attualmente stiamo usando RabbitMQ, ma so che passeremo al Microsoft Service Bus (on Premise) nel prossimo futuro.
Ho intenzione di creare una serie di interfacce e implementazioni in modo che quando passiamo a ServiceBus, devo semplicemente 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 è interamente dedicato agli spazi dei nomi e alle code. Inoltre, non ci sono interfacce comuni tra il client ServiceBus e il client RabbitMQ (ad esempio, entrambi possono avere una connessione IC, ma l'interfaccia è diversa, non da uno spazio dei nomi comune).
Quindi a mio punto, posso creare un'interfaccia come segue:
public interface IMessageReceiver{
void AddSubscription(ISubscription subscriptionDetails)
}
A causa delle proprietà non traducibili delle due tecnologie, le implementazioni ServiceBus e RabbitMQ dell'interfaccia di cui sopra hanno requisiti diversi. Quindi la mia implementazione RabbitMq di IMessageReceiver potrebbe apparire così:
public void AddSubscription(ISubscription subscriptionDetails){
if(!subscriptionDetails is RabbitMqSubscriptionDetails){
// I have a problem!
}
}
Per me, la linea sopra infrange la regola della sostituibilità di Liskov.
Ho pensato di capovolgerlo, in modo che una sottoscrizione accetti un IMessageConnection, ma ancora una volta la sottoscrizione RabbitMq richiederebbe proprietà specifiche di un RabbitMQMessageConnection.
Quindi, le mie domande sono:
- Sono corretto che questo rompe LSP?
- Siamo d'accordo sul fatto che in alcuni casi sia inevitabile o mi sto perdendo qualcosa?
Speriamo che sia chiaro e in tema!
interface IMessageReceiver<T extends ISubscription>{void AddSubscription(T subscriptionDetails); }
. Un'implementazione potrebbe quindi apparire public class RabbitMqMessageReceiver implements IMessageReceiver<RabbitMqSubscriptionDetails> { public void AddSubscription(RabbitMqSubscriptionDetails subscriptionDetails){} }
(in Java).
interface TestInterface<T extends ISubscription>
comunicarebbe chiaramente quali tipi sono accettati e che ci sono differenze tra le implementazioni.