Tło: opracowuję strukturę przesyłania wiadomości. Ramy te umożliwią:
- wysyłanie wiadomości za pośrednictwem magistrali usług
- subskrybowanie kolejek na szynie komunikatów
- subskrybowanie tematów na szynie wiadomości
Obecnie używamy RabbitMQ, ale wiem, że w najbliższej przyszłości przejdziemy do Microsoft Service Bus (w lokalu).
Planuję utworzyć zestaw interfejsów i implementacji, aby po przejściu na ServiceBus po prostu musiałem dostarczyć nową implementację bez zmiany żadnego kodu klienta (tj. Wydawców lub subskrybentów).
Problem polega na tym, że RabbitMQ i ServiceBus nie podlegają bezpośredniemu tłumaczeniu. Na przykład RabbitMQ opiera się na wymianach i nazwach tematów, podczas gdy ServiceBus dotyczy przestrzeni nazw i kolejek. Ponadto nie ma wspólnych interfejsów między klientem ServiceBus a klientem RabbitMQ (np. Oba mogą mieć połączenie IConnection, ale interfejs jest inny - nie od wspólnej przestrzeni nazw).
Moim zdaniem mogę utworzyć interfejs w następujący sposób:
public interface IMessageReceiver{
void AddSubscription(ISubscription subscriptionDetails)
}
Ze względu na nieprzekształcalne właściwości obu technologii, implementacje ServiceBus i RabbitMQ powyższego interfejsu mają różne wymagania. Więc moja implementacja IMessageReceiver w RabbitMq może wyglądać następująco:
public void AddSubscription(ISubscription subscriptionDetails){
if(!subscriptionDetails is RabbitMqSubscriptionDetails){
// I have a problem!
}
}
Dla mnie powyższa linia łamie zasadę substytucyjności Liskowa.
Rozważyłem odwrócenie tego, aby Subskrypcja akceptowała IMessageConnection, ale znowu Subskrypcja RabbitMq wymagałaby określonych właściwości RabbitMQMessageConnection.
Tak więc moje pytania to:
- Czy mam rację, że to łamie LSP?
- Czy zgadzamy się, że w niektórych przypadkach jest to nieuniknione, czy coś mi brakuje?
Mam nadzieję, że jest to jasne i na temat!
interface IMessageReceiver<T extends ISubscription>{void AddSubscription(T subscriptionDetails); }
. Implementacja może wtedy wyglądać następująco public class RabbitMqMessageReceiver implements IMessageReceiver<RabbitMqSubscriptionDetails> { public void AddSubscription(RabbitMqSubscriptionDetails subscriptionDetails){} }
(w java).
interface TestInterface<T extends ISubscription>
jasno komunikuje, które typy są akceptowane i że istnieją różnice między implementacjami.