Liskov Substitution Principle



2 dakikalık okuma
December 19, 2018

Üçüncü prensibimiz olan “Liskov Substitution Principle” da gerçekten çok önemli. Bu arada kod yazarken bu 5 prensibi göz önüne alarak kod yazmalıyız. Yani Ben sadece birinci prensibi takip ederek kod yazacağım diyemeyiz. Dikkat etmişinizdir ki, tüm prensipler de aslında uyum içinde. Hepsi birbirinin devamı ve birbirini tamamlıyor.

Neyse giriş yazsından sonra gelelim Liskov prensibinin kullanımına:

Öncelikle bu prensibin çıkış motivasyonu şöyledir:

Alt sınıflardan oluşturulan nesneler üst sınıfların nesneleriyle yer değiştirdiklerinde aynı davranışı göstermek zorundadırlar.

Şimdi örneklendirerek bu prensibi anlatmaya başlayalım:

1.Örnek:

class videoPlayer {
    public function play($file) {
        // play the file.
    }
}

class aviVideoPlayer  extends videoPlayer {
    public function play($file) {
        if (pathinfo($file,PATHINFO_EXTENSION)!==‘avi’) {
            throw new Exception;
        }
    }
}

Yukarıdaki örnek Liskov prensibini ihlal ediyor. Sebebi şu:

  • Birinci class videoPlayer sınıfı üst sınıf ve onun içinde bulunan play metoduna dikkatle bakın. Play metodunu işletirken direkt stream akışı başlıyor ve video oynatıyor.

  • İkinci class aviVideoPlayer extends videoPlayer sınıfı videoPlayer’ın alt sınıfı olup onun içerisindeki Play metoduna dikkat kesilin. Play metodu işletirilirken ilk başta uzantı kontrolü yaptırılıyor ve dosya uzantısı “avi” değilse hata mesajı ile uygulama sonlandırılıyor. Yani ikisinde çıkış davranışları farklı. Eğer uzantı kontrolü yapılacaksa birincisinde de yapılmalı. Yani üst sınıftaki nesnelerle alt sınıftaki nesneler yer değiştirdiğinde aynı davranışı göstermek zorunda. Birinde uzantı kontrolü ile hata mesajı verme davranışı var öbüründe yok. Bu olmaz!

2.Örnek:

Bu örneği de Interface ile yapalım:

Interface derslerDeposuInterface {
    public function hepsiniAl()
}


class dosyaDerslerDeposu implements derslerDeposuInterface {
    public function hepsiniAl() {
        return [];  // return değeri array tipinde
    }
}

class veritabaniDerslerDeposu implements derslerDeposuInterface {
    public function hepsiniAl() {
        // LSP prensibini ihlal ettik return değerinin JSON formatı olmasıyla.
        return dersler::all()->toJson(); // return  JSON formatında.   
    }
}

Yukarıdaki kod aşağıdaki metodda görülmek üzere LSP prensibini ihlal ediyor. Sebebi, return değerinin JSON formatı olması. Bir alt sınıf Array formatında, diğer öteki de -aşağıda görülmek üzere- JSON formatında.

class veritabaniDerslerDeposu implements derslerDeposuInterface {
    public function hepsiniAl() {
        // LSP prensibini ihlal ettik return değerinin JSON formatı olmasıyla.
        return dersler::all()->toJson(); // return değeri collection tipinde. JSON formatında.   
    }
}

Bu sorunu çözmek için kodları aşağıdaki gibi düzenliyoruz:

 <?php    
Interface derslerDeposuInterface {
    public function hepsiniAl() : Array;  // PHP 7.2 ve üstünde duck typing desteklediği için   problemi böyle çözüyoruz.
}

class dosyaDerslerDeposu implements derslerDeposuInterface {
    public function hepsiniAl() : Array {
        return [];  // return değeri array tipinde
    }
}
class veritabaniDerslerDeposu implements derslerDeposuInterface {
    public function hepsiniAl() : Array {
        return dersler::all()->toArray();  // array tipinde.
    }
}

Böylece LSP’ye uyumlu bir yapıya getirmiş olduk kodlarımızı. Hepsinin return değeri array. Çıkış verileri uyumlu tipte.


Etiketler: