Liskov Substitution Principle (LSP) Nedir?
Bu yazımızda, SOLID ilkelerinden “L” harfiyle temsil edilen “Liskov Substitution Principle” kavramına odaklanacağız.
Liskov Substitution Prensibi
Liskov Substitution Principle (LSP), 1987 yılında Barbara Liskov tarafından tanıtılmış ve daha sonra Jeannette Wing tarafından detaylandırılmış bir yazılım tasarım prensibidir. Adını, “substitution” kelimesinden alır; bu kelime Türkçeye “yerine koyma” veya “ikame” olarak çevrilebilir. Genel anlamda, bir şeyin başka bir şeyin yerine geçmesi veya bir şeyle değiştirilmesi anlamına gelir.
LSP, bir sınıf hiyerarşisinde alt sınıfların (child classes), üst sınıfların (parent classes) yerine geçebileceğini ve programın doğruluğunun bundan etkilenmemesi gerektiğini ifade eder. Başka bir deyişle:
- Alt sınıflar, üst sınıfların tüm özelliklerini ve davranışlarını korumalıdır.
- Üst sınıflar için yazılmış olan kod, alt sınıflarla da sorunsuz çalışmalıdır.
Bu prensip, alt sınıfların üst sınıfların işlevlerini değiştirmeden genişletebilmesini öngörür. Alt sınıflar, üst sınıfların davranışını bozacak veya beklenmeyen hatalara yol açacak şekilde hareket etmemelidir.
LSP’yi daha kolay anlamak için aktör-dublör ilişkisi üzerinden düşünebiliriz. Bir filmde, bir aktörün (üst sınıf) belirli bir sahnede oynayacağını varsayalım. Ancak bu sahne tehlikeli veya özel yetenekler gerektiriyorsa, yönetmen bir dublör (alt sınıf) kullanabilir.
LSP’ye göre:
- Dublör, aktörün yerine geçtiğinde sahnenin akışı veya filmin bütünlüğü bozulmamalıdır.
- Dublör, aktörün yapacağı tüm hareketleri aynı şekilde gerçekleştirebilmeli, hatta bazı ek hareketler de yapabilmelidir. Ancak, dublör sahneyi değiştirecek veya hikayeyi bozacak bir şey yaparsa bu prensibe aykırı olur.
Aşağıdaki Python kodunda, bir Bird sınıfı ve ondan türetilmiş Eagle ve Ostrich sınıfları bulunuyor:
class Bird:
def fly(self):
pass
class Eagle(Bird):
def fly(self):
return "Eagle can fly"
class Ostrich(Bird):
def fly(self):
raise Exception("Ostriches cannot fly")
Bu örnekte:
- Eagle sınıfı, Bird sınıfının
fly
metodunu uygun şekilde genişletmiştir. - Ancak Ostrich sınıfı, bu metodu değiştirerek hata fırlatmaktadır.
Eğer bir fonksiyon, Bird tipinde bir nesne bekliyorsa ve bu nesne Ostrich ise, program beklenmedik bir hatayla karşılaşabilir. Bu durum LSP’ye aykırıdır çünkü alt sınıf (Ostrich), üst sınıfın (Bird) beklenen davranışını değiştirmiştir.
Aşağıdaki örnekte, bir Shape sınıfı ve ondan türetilmiş Rectangle ve Square sınıfları bulunuyor:
class Shape:
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Square(Rectangle):
def __init__(self, size):
super().__init__(size, size)
Bu örnekte:
- Rectangle sınıfı, şekillerin alanını hesaplamak için bir yöntem sunuyor.
- Square sınıfı, Rectangle sınıfından türetilmiş ve
area
metodunu aynı şekilde koruyor.
Bu yapıda, Square nesnesi, Rectangle nesnesinin yerine kullanılabilir ve programın işleyişi bozulmaz. Yani, üst sınıfın beklenen davranışları korunur ve LSP’ye uygun bir tasarım elde edilir.
Neden LSP’ye Uymak Önemlidir?
- Kodun Yeniden Kullanılabilirliği: Alt sınıflar, üst sınıfların yerine kullanılabilir olduğunda, kod daha esnek ve yeniden kullanılabilir hale gelir.
- Bakım Kolaylığı: LSP’ye uyan kod, tahmin edilebilir ve daha az hata içerir, bu da bakımını kolaylaştırır.
- Uzmanlaşma: Alt sınıflar, üst sınıfların genel işlevlerini korurken, kendi özelliklerini de ekleyebilir.
- Hata Riskini Azaltır: Alt sınıfların üst sınıf davranışlarını bozmadığından emin olmak, büyük sistemlerde olası hataları engeller.
Liskov Substitution Principle, yazılım tasarımında sağlam ve sürdürülebilir bir yapı oluşturmanın temel taşlarından biridir. Prensibin uygulanmadığı durumlarda:
- Kodun güvenilirliği azalır.
- Karmaşık sistemlerde beklenmedik hatalar oluşabilir.
- Kod tekrar kullanılabilir ve genişletilebilir olmaktan çıkar.
Özetle, LSP’ye uygun tasarımlar, yazılım geliştirme süreçlerinde daha esnek, güvenilir ve sürdürülebilir bir yapı sağlar.