Merhaba bir önceki yazımda SOLID
Prensiplerinden O 'ya denk gelen Open/Closed
Principle' ı anlatmıştım.
Şimdi de L 'ye denk gelen Liskov's Subtitution Principle yani Liskov'un Yerine
Geçme Prensibinden bahsediyor olacağım. Bu prensibi aslında OCP ile hemen hemen
aynı kapıya çıkan, fakat biraz daha özelleşmişi olarak düşünebilirsiniz.
1987-88 yıllarında Barbara Liskov'un dediği cümleye bakacak olursak ;
"Let q(x) be a property provable about objects x of type T.
Then q(y) should be provable for objects y of type S where S is a subtype of T."
Görüldüğü üzere ingilizcesi gayet açık. Bide Türkçesini verecek olursak;
“q(x)
fonksiyonu T tipindeki x nesnesi için kanıtlanabilirdir. O halde T tipinin alt
tipi olan S tipindeki y nesnesi için de q(y) fonksiyonu kanıtlanabilir
olmalıdır.”
Barbara hanımefendinin diğer bir tanımında ise şöyle diyor;
"Aranan yer
değiştirme özelliği şöyle tanımlanabilir: T cinsinden parametre alan tüm
programlar (fonksiyonlar) P olacak şekilde, S tipinde O1 nesnesi ve T tipinde O2 nesnesi olsun. Eğer O1 ile O2 nesneleri yer değiştirdiğinde P’nin davranışı
değişmiyorsa S tipi T tipinin alt tipidir!"
Bu tanım daha bi basit oldu sanki,
anladığınızı umuyorum..Tabi ki anlamadınız :) Her iki tanımdan da hiç bir şey anlaşılmayacağı aşikar. Ama üzülmeye gerek yok bunu ilk
okuyan kimse anlamıyor zaten emin olabilirsiniz. Konu yıllarca "Acaba ablamız ne demek istiyor?" lakırdıları eşliğinde anlaşılmadığı için, en sonunda bu anlamsızlığa dayanamayan Robert Martin amcamız;
"Subtypes must be substitutable for their base types."
diyerek son noktayı koyar. Nispeten daha anlaşılır bir kavram olan bu sözün meali ise;
"Alt sınıflardan oluşan nesnelerin, üst sınıfla yer değiştirdiği
zaman aynı davranışları göstermek zorundadırlar"
şeklindedir. Biz bunu biraz daha açıp, biraz daha bizden hale getirirsek üst sınıf ve ondan türeyen alt sınıfların birbiriyle birebir uyumlu olması gerekir diyebiliriz. Üst sınıfta olup da alt sınıfın kullanmayacağı bir özellik, method, fonksiyon vb. şeyler olmamalıdır. Bu olduğu takdirde alt sınıfın kullanmadığı özellikler için ekstra kodlar ve kontroller yazılması gerekir ki bu hem OCP hem de Liskov'a ters düşer. Tanımlardan da anlaşılacağı gibi aslında OCP ve Liskov pensipleri iç içe geçmiş durumdadırlar. Liskov prensibine ters olan bir durum otomatik olarak OCP 'ye de terstir denilebilir.Durumu basit ama etkili bir örnekle anlatmaya çalışalım.
Örnek - 1:
Uçak filomuz olduğunu düşünüyoruz ve bu filo da her tip uçağın yer aldığını göz önüne bulunduralım. Öncelikle hatalı tasarımı çıkarmamız gerekirse;
IUcak interface'i yazılmış ve tüm uçaklar bu interface üzerinden türetilmiştir. Fakat sorun şudur ki, interface deki methodlar zorunlu olarak implemente edilmek durumunda kalmışlardır. Genele bakıldığı zaman savaş uçağının bombalama fonksiyonu olabilir, ama yolcu uçağının böyle bir fonksiyonu yoktur. Bu durumda ana programda "Bombala()" methodu yazılırken ekstra kontrol yapılmak zorunda kalınmıştır. Bu yapı OCP 'ye zaten uymadığı gibi Liskova da uymaz. Liskova uymama sebebi, üst sınıfın her özelliğinin alt sınıfta yer almamasıdır, yolcu uçağının bombalama fonksiyonu yoktur. Düşünün ki yolcu uçağına Bombala butonu koydunuz ve arkasını boş bıraktınız. Düğmeye basınca ya hata alacaksınız, yada hiç bir tepki almayacaksınız ki hata almak istemiyorsanız üstte yapılan gibi taklalar atmak zorunda kalacaksınız. İşte bu Liskov bu tarz Dummy (sahte kod) durumlarına hayır demektedir. Yani buton varsa, işlevi de olmalı :)
Liskov prensibine göre bu uçakların birbiri yerine kullanılabilmesi gerekmektedir. O halde bir sınıfta yer alan herhangi bir işlev kendisinden kalıtım alınan herhangi bir sınıfta kullanılamıyorsa bu durum Liskov prensibine aykırıdır denilebilir. Bu durumda Interfaceleri ayırmak yöntemiyle Liskova uygun hale getirilir.
Aslında burada konuların birbiriyle aşırı bağlantılı olduğunu, hatta yer yer iç içe girdiğini farketmişsinizdir, çünkü SOLID'in I'sına denk gelen Interface Segregation Principle kuralını da aslında siz farkına varmadan anlatmış oldum :)
Örnek - 2:
Şimdi ki örneğimizde de araba üreten fabrikamızın yazılımını kodladığımızı hayal edelim ve arabanın olmazsa olmazı "Calistir()" metodu ve günümüzdeki hemen her araba da olan "KlimaCalistir()" metodunu bir abstract class yazarak tanımlayalım. Önce hatalı kurgudan bahsedersek aşağıdaki gibi olacaktır.
Arabanın Ferrari, Mustang, Porcshe olduğu durumlarda sıkıntı yok ama, Murat131 yada Tofaş Doğan Slx olduğu durumlarda ne yapalım :) Yukarıdaki gibi bir tasarımda mecburen Tofas sınıfında ilgili metoda "Null" return ettirmek, yada "KlimaCalistir()" metodunu kullanmamak gerekir, ama ya projeyi ilk açan ekip arkadaşımız bu şekilde çağırırsa..İşte büyük projelerde o zaman buyurun cenaze namazına. Bunun önüne geçmenin yolu olarak hemen LSP 'ye uygun hale getirirsek;
Örnek - 3:
Aşağıdaki örnekte de bir e-ticaret sitesi için Standart,Gold ve Platinum üyelik tipinde müşteriler olduğunu düşünelim. Bu müşterilerden sadece Gold ve Platinum tipi üye müşterilere hediye gönderilebildiğini varsayan bir tasarımı görebilirsiniz.
Örnek - 4:
Son örneğimizde de bağımsız bir DB Erişim katmanı tasarımına yer verelim
Bunlar verilebilecek örneklerden sadece bir kaç tanesi. Siz de hayal gücünüzü kullanarak bir çok içinden çıkılmaz durumu bu şekilde daha net, daha akıcı hale getirebilirsiniz. Özetle Liskov prensibini uygularsanız ;
1 - Olması gereken kodun, olması gerektiği yerde olmasından emin olursunuz.
2 - Fazla kod yazmamış olursunuz
3 -Grup içinde yazılan kodlarda standartları ekibinizle birlikte yakalamış, hataya mümkün mertebe "Sıfır" tolerans tanımış olursunuz.
Böylelikle SOLID' in L'si olan Liskov prensibini de anlatmış oldum. Bir sonraki yazım olacak olan SOLID'in I'sına denk gelen Interface Segregation Principle 'da görüşmek üzere.
Hiç yorum yok:
Yorum Gönder