Gerçek Dünya - Liskov İkame İlkesi


14

Arka plan: Bir mesajlaşma çerçevesi geliştiriyorum. Bu çerçeve şunları sağlayacaktır:

  • servis otobüsü üzerinden mesaj gönderme
  • mesaj veri yolundaki kuyruklara abone olma
  • mesaj veri yolundaki konulara abone olma

Şu anda RabbitMQ kullanıyoruz, ancak çok yakında Microsoft Hizmet Veri Yolu'na (Şirket İçi) taşınacağımızı biliyorum.

Bir dizi arabirim ve uygulama oluşturmayı planlıyorum, böylece ServiceBus'a taşındığımızda, istemci kodunda (yani yayıncılar veya aboneler) herhangi bir değişiklik yapmadan yeni bir uygulama sağlamam gerekiyor.

Buradaki sorun, RabbitMQ ve ServiceBus'un doğrudan çevrilebilir olmamasıdır. Örneğin, RabbitMQ Değişimler ve Konu Adlarına dayanırken, ServiceBus tamamen Ad Alanları ve Kuyruklarla ilgilidir. Ayrıca, ServiceBus istemcisi ile RabbitMQ istemcisi arasında ortak arabirimler yoktur (örneğin her ikisinde de bir IConnection olabilir, ancak arabirim farklıdır - ortak bir ad alanından değil).

Benim açımdan, aşağıdaki gibi bir arayüz oluşturabilirim:

public interface IMessageReceiver{
  void AddSubscription(ISubscription subscriptionDetails)
}

İki teknolojinin çevrilemez özelliklerinden dolayı, yukarıdaki arabirimin ServiceBus ve RabbitMQ uygulamaları farklı gereksinimlere sahiptir. Yani IMessageReceiver benim RabbitMq uygulaması şöyle görünebilir:

public void AddSubscription(ISubscription subscriptionDetails){
  if(!subscriptionDetails is RabbitMqSubscriptionDetails){
    // I have a problem!
  }
}

Bana göre, yukarıdaki çizgi Liskov'un ikame edilebilirlik kuralını ihlal ediyor.

Bir Abonelik bir IMessageConnection kabul eder, ancak yine de RabbitMq Abonelik bir RabbitMQMessageConnection belirli özellikleri gerektirir bu etrafında saygısız kabul.

Yani, sorularım:

  • Bunun LSP'yi bozduğunu düzeltir miyim?
  • Bazı durumlarda bunun kaçınılmaz olduğunu kabul ediyor muyuz, yoksa bir şey mi kaçırıyorum?

Umarım, bu açık ve konuyla ilgili!


Arabirime bir tür parametresi eklemek sizin için bir seçenek mi? Java-sözdizimi açısından, interface TestInterface<T extends ISubscription>hangi türlerin kabul edildiğini ve uygulamalar arasında farklılıklar olduğunu açıkça bildirir.
Hulk

@Hulk, inanmıyorum, çünkü her uygulama farklı bir ISubscription uygulamasını gerektirecektir.
GinjaNinja

1
Üzgünüm, önermek istediğim şey buydu interface IMessageReceiver<T extends ISubscription>{void AddSubscription(T subscriptionDetails); }. Bir uygulama public class RabbitMqMessageReceiver implements IMessageReceiver<RabbitMqSubscriptionDetails> { public void AddSubscription(RabbitMqSubscriptionDetails subscriptionDetails){} }(java'da) gibi görünebilir .
Hulk

Yanıtlar:


11

Evet, LSP'yi bozar, çünkü kabul edilen değerlerin sayısını sınırlayarak alt sınıfın kapsamını daraltırsınız, ön koşulları güçlendirirsiniz. Ebeveyn kabul ettiğini belirtir, ISubscriptionancak çocuk kabul etmez.

Kaçınılmaz olup olmadığı tartışma konusudur. Bu senaryodan kaçınmak için tasarımınızı tamamen değiştirebilir misiniz, belki de üreticilerinize bir şeyler iterek ilişkiyi tersine çevirebilir misiniz? Bu şekilde, veri yapılarını kabul eden arayüzler olarak beyan edilen hizmetleri değiştirirsiniz ve uygulamalar, onlarla ne yapmak istediklerine karar verir.

Diğer seçenek, API kullanıcısının, kabul edilemez bir alt türdeki bir durumun ortaya çıkabileceğini, örneğin, atılabilecek bir istisna ile arabirime açıklama ekleyerek açıkça bildirmesini sağlamaktır UnsupportedSubscriptionException. İlk arabirimin modellenmesi sırasında katı önkoşul hakkını tanımlamanız ve hatanın neden olduğu uygulamanın geri kalanını etkilemeden türün doğru olması durumunda istisna atmadan zayıflamasına izin verilir.


Teşekkürler. Sadece sorunu taşımadan nasıl 'çevireceğim' düşünemiyorum. Örneğin, aboneliğin mesajı almak için RabbitMQ için IModel ve ServiceBus için başka bir şey bilmesi gerekir. Açıklamalı istisnanın ileriye giden tek yol olduğunu düşünüyorum.
GinjaNinja

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.