Liskov Substitution Principle Nedir?
LSP prensibi Open-Closed prensibinin özel bir türüdür desek yanlış olmaz. OCP’de de olduğu gibi LSP de de genişlemeye açık yapılar söz konusudur. Her ne kadar anlaşılması biraz zor olsa da LSP ilk bakışta, altında yatan ana fikri: alt sınıflardan oluşan nesnelerin üst sınıfın nesneleri ile yer değiştirdikleri zaman, aynı davranışı sergilemesini beklemektir.
Basit bir örnek ile hemen inceleyelim:
Örneğimizde soyut(abstract) olarak bir Car sınıfını tanımlıyoruz ve içerisine Run ve OpenAirConditioning metotlarını ekliyoruz.
namespace LiskovSubstitutionPrinciple
{
public abstract class Car :
{
public string Run()
{
return "Araba çalıştırıldı.";
}
public abstract string OpenAirConditioning();
}
}
Kalıtım alnacak Run metotu ile araba çalıştırılacak, soyut(abstract) olarak tanımlanmış OpenAirConditioning metotu ilede kalıtım alan türe göre klima açılacak.
Ardından Ferrari ile Murat131 somut sınıflarını (concreate) Car soyut sınıfından kalıtım yoluyla oluşturuyoruz. Burada dikkatin çekilmesi gereken nokta: Murat131’in klima özelliğinin olmamasından dolayı ve soyut(abstract) olarak tanımlanmış metotu override etmek zorunda olduğumuz için ya NotImplementedException hatası fırlatılacak yada null geçerek hatanın üzerini örtmüş olacağız.
public class Ferrari : Car
{
public override string Run(){
return "Araba Çalıştı";
}
public override string OpenAirConditioning()
{
return "Klima açıldı.";
}
}
public class Murat131 : Car
{
public override string Run (){
return "Araba Calıstı";
}
public override string OpenAirConditioning()
{
throw new NotImplementedException();
//return null;
}
}
Buraya kadar her şey güzel. Murat131’in kliması olsun olmasın ben null geçtim ve hataya engel oldum diye düşünüyoruz. Ne olabilir ki? Evet çok şey olabilir! Eğer büyük bir proje ekibi ile aynı proje üzerinde çalışıyorsak ve günlerden bir gün bir kodu başka bir yazılımcı ihtiyaç duyuyorsa ve şöyle bir şeyler kodlamaya başlarsa:
static void Main(string[] args)
{
Car car = new Ferrari();
car.Run();
car.OpenAirConditioning();
// Sıkıntı yok her şey yolunda.
car = new Murat131();
car.Run();
car.OpenAirConditioning(); // ?
}
Ferrari için her şey güllük gülistanlık olurken aynı davranış Murat131 için olmayacaktır ve o ekip arkadaşınızdan hiç de hoş olmayan laflar duyabilirsiniz helede bir test ekibiniz yoksa ve ürününüzü production ortamına çıkartıyorsanız vay halinize…
LSP’ye girişteki ilk sözü hemen hatırlayalım tekrar: alt sınıflardan oluşan nesnelerin üst sınıfın nesneleri ile yer değiştirdikleri zaman, aynı davranışı sergilemesini beklemektir.
Bu durumda Murat131 aynı davranışı sergilememesinden dolayı LSP’ye uymadığını söyleyebiliriz. Ayrıca, OpenAirConditioning özelliğini temel sınıfımız olan Car sınıfından bir Interface(arayüz) aracılığı ile ayırabilir ve ilgili somut sınıfa (concreate class) implemente ederek bu problemin önüne geçmiş olabiliriz. Hatırlayalım: interface’de genelde can-do ilişkisi vardı, bir edinim kazandırma.
Hemen klima için olan IAirConditionable arayüzünü(interface) oluşturalım ve ilgili sınıfa implemente edelim.
Not: interface’ler genelde başlarında I takısı ve sonunda -able takısı almaktadır. -ebilen gibi bir edinim kazandırma durumlarında.
using System;
namespace LiskovSubstitutionPrinciple
{
public interface IAirConditionable
{
string OpenAirConditioning();
}
public abstract class Car
{
public string Run()
{
return "Araba çalıştırıldı.";
}
}
public class Ferrari : Car, IAirConditionable
{
public string OpenAirConditioning()
{
return "Klima açıldı.";
}
}
public class Murat131 : Car
{
public override string Run()
{
return "Araba Çalıştı.";
}
}
}
Klima özelliğini sadece Ferrari için implemente ettiğimizden dolayı, hiç kimse Murat131 için OpenAirConditioning metotuna erişemiyecek ve herhangi bir problem ile karılaşılmayacaktır.
Last updated
Was this helpful?