Liskov Substitution Yazılım Prensibi
Liskov Substitution(Liskov’un Yerine Geçme Prensibi), yaratılan alt sınıflar, üst sınıflardan kalıtım alırken, üst sınıfların tüm özelliklerini kullanabilmesi gerektiğini söyleyen bir tasarım prensibidir. Yani bir özellik gereksiz yere kalıtım yolu ile alınmamalıdır.
“Temel (base) sınıfın işaretçisini (pointer) ya da referansını kullanan fonksiyonlar, bu sınıftan türemiş olan (derived) sınıfları da ekstra bilgiye ihtiyaç duymaksızın kullanabilmelidir.” — Robert C. Martin (Bob Amca)
Bu prensip aslında Open/Closed Prensibi’ne benzer, özel bir türü diyebiliriz. Her ikisinde de genişlemeye açık yapılar söz konusudur.

Liskov’un yerine geçme prensibi aslında OOP prensiplerinden Polymorphism (Çok biçimlilik) ile yakından ilgilidir. Hadi bir örnek ile daha iyi anlayalım, önceki prensipte kullandığımız örnek üzerinden ilerleyeceğiz.
Örneğimiz şöyle, bir Interface tanımlıyoruz. Diğer sınıflarımız bundan kalıtım alıp, OpenLock metodu ile telefonun kilidi açılacak, AddTouchId() metodu ile telefona bir biyometrik şifre koyulacaktır.

Ardından Iphone, Samsung ve Xiaomi somut(concreate) sınıflarını IMobilePhone interface’i ile kalıtım yoluyla oluşturuyoruz. Artık hazırız, tüm telefonlarımızın kilidini açıp, hepsine teker teker TouchId Biyometrik kilidi koyuyoruz.

İşlem tamamdır, peki ya şimdi bu uygulamaya bir telefon daha ekleyelim. Artık efsane kasa Nokia 3310 telefonuna bu işlemleri uygulamak istiyoruz! Amanın Nokia’da TouchId diye bir özellik yok! IMobilePhone interface’imiz içerisindeki elemanları zorla uygulatmaktadır. Burada Nokia için AddTouchId() metodu gereksizdir. Ee şimdi ne yapacağız ?

Hemen harekete geçip, Nokia için artık bir şart koyduk. Biz herşey için böyle if/else yaparak mı gideceğiz peki ? Haliyle LSP’ye aykırı olan bu durum OCP’ye de aykırıdır. En kötü NotImplementedException koyup try/catch bloğunda yakalarız dimi. 😅
Gelin şimdi Liskov Substitution Prensibi’ni uygulayarak çözelim.

Iphone, Samsung ve Xiaomi hem kilit açma hemde biyometrik özelliklere sahip oldukları için iki interface’den kalıtım almaktadırlar. Nokia ise sadece kilit açma yapabileceği için sadece ILockable interface’inden kalıtım almaktadır. Bu sayede kullanmayacağı bir işlev olan AddTouchId() metodunu barındırmak zorunda kalmayacaktır.
Görüldüğü üzere base objemizi arayüzlere bölmüş bulunmaktayız. Bu yaptığımız işlem Arayüz Ayrım Prensibi(Interface Segregation Principle)’ne uyarlı bir yaklaşımdır.
Not: Interface’ler genelde başlarında I takısı ve sonunda -able takısı almaktadır.

İşte Bu Kadar! Neler Yaptık ?
- Kodumuzu biraz daha generic yapıp, Condition(if/else) bağımlılığını sildik.
- Değişiklik değil aksine gelişimsellik söz konusu olduğu için Open/Closed Prensibi’ne uygun bir tasarım yaptık.
- Her yapı tek bir işi yaptığı için Single Responsibility Prensibi’ne uygun bir tasarım yaptık.
- Interface’leri kullanarak özellikleri ayırdık. Bu sayede Interface Segregation Prensibi’ne uygun tasarım yaptık.
ÖZET
LSP, hem yeni bir uygulama geliştirirken hem de mevcut bir uygulamayı geliştirirken veya değiştirirken akılda tutulması gereken çok faydalı bir fikirdir.
Yeni bir uygulama için sınıf hiyerarşisini tasarlarken, LSP, problem alanımızdaki kavramları düzenlememize ve geleceğe yönelik kod yazmamıza yardımcı olur.
Okuduğunuz için Minnettarım.
Sağlıcakla kalın Dostlarım..
SOLID prensiplerine devam etmek için Interface Segregation Prensibi’ne göz atabilirsiniz;
👉 Interface Segregation Principle (ISP) — SOLID
Kaynakça
What is Liskov Subsititutions Principle (Important)
Liskov Subsititutions With C# (Special Thanks)
LSP Abstraction Examples (Special Thanks)

