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!
la source
interface TestInterface<T extends ISubscription>
cela communiquerait clairement quels types sont acceptés et qu'il existe des différences entre les implémentations.interface IMessageReceiver<T extends ISubscription>{void AddSubscription(T subscriptionDetails); }
. Une implémentation pourrait alors ressemblerpublic class RabbitMqMessageReceiver implements IMessageReceiver<RabbitMqSubscriptionDetails> { public void AddSubscription(RabbitMqSubscriptionDetails subscriptionDetails){} }
(en java).Réponses:
Oui, cela casse le LSP, car vous réduisez la portée de la sous-classe en limitant le nombre de valeurs acceptées, vous renforcez les conditions préalables. Le parent spécifie qu'il accepte,
ISubscription
mais pas l'enfant.Que ce soit inévitable est une chose à discuter. Pourriez-vous peut-être changer complètement votre conception pour éviter ce scénario, peut-être inverser la relation en insérant des éléments dans vos producteurs? De cette façon, vous remplacez les services déclarés en tant qu'interfaces acceptant les structures de données et les implémentations décident de ce qu'ils veulent en faire.
Une autre option consiste à informer explicitement l'utilisateur de l'API, qu'une situation d'un sous-type inacceptable peut se produire, en annotant l'interface avec une exception qui pourrait être levée, telle que
UnsupportedSubscriptionException
. En faisant cela, vous définissez le droit de pré-condition strict lors de la modélisation de l'interface initiale et vous êtes autorisé à l'affaiblir en ne levant pas l'exception si le type est correct sans affecter le reste de l'application qui explique l'erreur.la source
Oui, votre code casse LSP ici. Dans de tels cas, j'utiliserais Anti-Corruption Layer de DDD Design Patterns. Vous pouvez voir un exemple ici: http://www.markhneedham.com/blog/2009/07/07/domain-driven-design-anti-corruption-layer/
L'idée est de réduire autant que possible la dépendance au sous-système en l'isolant explicitement, pour minimiser le refactoring lors du changement
J'espère que cela aide !
la source