Temel olarak olayların mantıklı davranmasını istiyoruz.
Aşağıdaki sorunu göz önünde bulundurun:
Bana bir grup dikdörtgen verildi ve alanlarını% 10 artırmak istiyorum. Yaptığım şey, dikdörtgenin uzunluğunu öncekinden 1.1 kat daha fazla ayarlamam.
public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles)
{
foreach(var rectangle in rectangles)
{
rectangle.Length = rectangle.Length * 1.1;
}
}
Şimdi bu durumda, tüm dikdörtgenlerim artık uzunluklarını% 10, alanlarını% 10 artıracak. Ne yazık ki, birisi aslında bana kareler ve dikdörtgenlerin bir karışımını iletti ve dikdörtgenin uzunluğu değiştiğinde, genişlik de öyle oldu.
Birim testlerim başarılı oldu çünkü tüm birim testlerimi bir dikdörtgen koleksiyonu kullanmak için yazdım. Şimdi başvurumda aylarca farkedilemeyecek ince bir böcek tanıttım.
Daha da kötüsü, muhasebeden Jim, yöntemimi görüyor ve kareleri benim yöntemime geçirirse, boyutunda% 21'lik çok güzel bir artış elde ettiği gerçeğini kullanan başka bir kod daha yazıyor. Jim mutlu ve kimse bilge değil.
Jim, mükemmel çalışmalar için farklı bir bölüme terfi etti. Alfred şirkete junior olarak katılır. İlk hata raporunda, Advertising'den Jill, karelerin bu yönteme geçmesinin% 21 artışla sonuçlandığını ve hatanın düzeltilmesini istediğini bildirdi. Alfred, Karelerin ve Dikdörtgenlerin kodun her yerinde kullanıldığını görür ve kalıtım zincirinin kırılmasının imkansız olduğunu fark eder. Ayrıca, Muhasebenin kaynak koduna da erişimi yok. Öyleyse Alfred böyle bir hatayı düzeltir:
public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles)
{
foreach(var rectangle in rectangles)
{
if (typeof(rectangle) == Rectangle)
{
rectangle.Length = rectangle.Length * 1.1;
}
if (typeof(rectangle) == Square)
{
rectangle.Length = rectangle.Length * 1.04880884817;
}
}
}
Alfred, uber hack becerilerinden memnundur ve Jill, hatanın düzeltildiğini onaylar.
Gelecek ay kimse ödeme yapmıyor çünkü Muhasebe IncreaseRectangleSizeByTenPercent
metoda kareleri geçebilmeye ve% 21'lik bir alanda artış elde etmeye bağlıydı . Tüm şirket, sorunun kaynağını bulmak için "öncelik 1 hata düzeltme" moduna geçer. Sorunu Alfred'in düzeltmesine kadar takip ediyorlar. Hem Muhasebe hem de Reklamcılık'ı mutlu etmeleri gerektiğini biliyorlar. Böylece, kullanıcıyı böyle bir yöntem çağrısı ile tanımlayarak sorunu çözdüler:
public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles)
{
IncreaseRectangleSizeByTenPercent(
rectangles,
new User() { Department = Department.Accounting });
}
public void IncreaseRectangleSizeByTenPercent(IEnumerable<Rectangle> rectangles, User user)
{
foreach(var rectangle in rectangles)
{
if (typeof(rectangle) == Rectangle || user.Department == Department.Accounting)
{
rectangle.Length = rectangle.Length * 1.1;
}
else if (typeof(rectangle) == Square)
{
rectangle.Length = rectangle.Length * 1.04880884817;
}
}
}
Ve diğerleri ve diğerleri.
Bu fıkra, günlük olarak programcıların karşılaştığı gerçek dünya durumlarına dayanmaktadır. Liskov Değişimi ilkesinin ihlali, yalnızca yazıldıktan yıllar sonra toplanan çok ince böcekler ortaya çıkarabilir; bu süre zarfında ihlali düzeltmek bir çok şeyi kıracak ve düzeltmemek en büyük müşterinizi kızdıracaktır.
Bu sorunu çözmenin iki gerçekçi yolu vardır.
İlk yol, Dikdörtgen'u değişmez kılmaktır. Dikdörtgen kullanıcısı Uzunluk ve Genişlik özelliklerini değiştiremezse, bu sorun çözülür. Farklı uzunluk ve genişlikte bir Dikdörtgen istiyorsanız, yeni bir tane oluşturun. Kareler dikdörtgenlerden mutlu bir şekilde miras alabilir.
İkinci yol ise kalıtım zincirini kareler ve dikdörtgenler arasında kırmaktır. Bir karenin tek bir SideLength
özelliğe sahip olması ve dikdörtgenlerin bir Length
ve Width
özelliğine sahip olması tanımlanırsa ve kalıtım olmazsa, bir dikdörtgen bekleyerek ve bir kare alarak şeyleri kazara kırmak imkansızdır. C # terimleriyle, aldığınız seal
tüm Dikdörtgenlerin gerçekte Dikdörtgenler olmasını sağlayan dikdörtgen sınıfınız olabilir .
Bu durumda, sorunu çözmenin "değişmez nesneler" şeklini seviyorum. Bir dikdörtgenin kimliği uzunluk ve genişliktir. Bir nesnenin kimliğini değiştirmek istediğinizde, gerçekten istediğiniz şeyin yeni bir nesne olduğu anlamına gelir. Eski bir müşteriyi kaybeder ve yeni bir müşteri kazanırsanız, Customer.Id
alanı eski müşteriden yenisine değiştirmezsiniz, yeni bir şey yaratırsınız Customer
.
Liskov Değişimi ilkesinin ihlali gerçek dünyada yaygındır, çünkü çoğunlukla yetersiz olan / zaman baskısı altında olan / umursamayan / hata yapmayan kişiler tarafından yazılmış birçok kod vardır. Bazı çok kötü sorunlara yol açabilir ve açabilir. Çoğu durumda, miras yerine kompozisyonu tercih etmek istersiniz .