Interface Segregation Principle (Interface Ayrımı İlkesi)

Ana Sayfa Blog Interface Segregation Principle (Interface Ayrımı İlkesi)

Interface Segregation Principle (Interface Ayrımı İlkesi)

Bu makalede SOLID prensiplerinin dördüncü maddesinden söz edeceğiz. "Neydi bu prensipler?" diye mi sordunuz, buyurun, özet makaleyi inceleyin.

Interface Ayrımı İlkesi bir interface'in hiçbir implementasyonunun, kullanmayacağı metodlara bağlı olmaya zorlanamayacağını söyler. Bir interface'in ihtiyacınız olmayan metodlarını implemente etmek zorunda kaldınız mı? Eğer kaldınızsa, implementasyonunuz içinde büyük ihtimalle boş metodlar oluşturmuşsunuzdur. Bu, bir interface kullanmaya zorlamanın bir örneği olup Interface Ayrımı ilkesini bozmaktadır.

Pratik açıdan bakıldığında, bu ilke interface'lerin taneli ve odaklı olmasını istiyor. Tanıdık geliyor mu? Hatırlayınız, beş SOLID ilkesinin hepsi birbiriyle ilişkilidir ve bunlardan birini bozmakla sıklıkla diğerlerini de bozmuş olursunuz. Interface Ayrımı ilkesi bozulduğu zaman, Tek Bir Sorumluluk ilkesi de bozulmuş olacaktır.

Tüm implementasyonlar tarafından gerekli olmayan metodları içeren "şişkin" bir interface'e sahip olmak yerine, gerekli oldukça tek tek implemente edilebilen birkaç daha küçük interface'e sahip olmak tercih edilir. Şişkin interface'lerin daha küçük, daha odaklı sözleşmeler haline bölünmesiyle, alıcı kod kullanmayacağı uygulama parçalarına bağımlılık oluşturmaksızın daha küçük bir interface'e bağımlı olabilecektir.

Interface Ayrımı İlkesi

Bu ilke, bir interface'in hiçbir implementasyonunun, kullanmayacağı metodlara bağlı olmaya zorlanamayacağını belirtir.

Bu ilkeyi göstermek için, örnek bir oturum işleme kitaplığını ele alalım. Gerçekten de, PHP'nin kendi `SessionHandlerInterface`ini ele alacağız. PHP'nin 5.4 sürümünden itibaren dahil edilen bu interface tarafından tanımlanmış metodlar şöyledir:

interface SessionHandlerInterface {
    public function close();
    public function destroy($sessionId);
    public function gc($maxLiftetime);
    public function open($savePath, $name);
    public function read($sessionId);
    public function write($sessionId, $sessionData);
}

Şimdi bu interface tarafından tanımlanan metodlar hakkında bilgi sahibi oldunuz, Memcached kullanan bir implementasyon düşünelim. Bu interface'in bir Memcached implementasyonu bu metodların her biri için fonksiyonellik tanımlayacak mıdır? Bu metodların hepsini implemente etmemize gerek olmadığı gibi, bunların yarısına hiç ihtiyacımız yoktur!

Memcached taşıdığı değerleri otomatik olarak sonlandırdığı için, interface'in gc metodunu implemente etmemize gerek yoktur, interface'in open veya close metodlarını da implemente etme ihtiyacında değiliz. Dolayısıyla, implementasyonumuz içinde bu metodlar için sadece boş metodlar olan "kısımlar" tanımlamaya zorlanıyoruz. Bu problemi düzeltmek için, oturum çöp toplaması için daha küçük, daha odaklı bir interface tanımlamakla başlayalım:

interface GarbageCollectorInterface {
    public function gc($maxLifetime);
}

Şimdi daha küçük bir interface'imiz oldu, herhangi bir alıcı kod çok dar bir fonksiyonelliği tanımlayan ve bütün bir oturum işleyicisine bir bağımlılık oluşturmayan bu odaklı sözleşmeye bağımlı olacaktır.

Bu ilkenin daha iyi anlaşılması için, başka bir örnekle bilgimizi pekiştirelim. Şu şekilde tanımlanmış bir Contact Eloquent sınıfımız olduğunu düşünelim:

class Contact extends Eloquent {

    public function getNameAttribute()
    {
        return $this->attributes['name'];
    }

    public function getEmailAttribute()
    {
        return $this->attributes['email'];
    }

}

Şimdi, varsayalım ki bizim uygulamamız, kullanıcılarına şifre hatırlatıcı e-postalar göndermekten sorumlu bir PasswordReminder sınıfını da istihdam ediyor. PasswordReminder sınıfının olası bir tanımı aşağıdadır:

class PasswordReminder {

    public function remind(Contact $contact, $view)
    {
        // Şifre hatırlatıcı e-postası gönder...
    }

}

Büyük ihtimalle fark etmiş olabileceğiniz gibi, bu PasswordReminder sınıfımız Contact sınıfına bağımlıdır, o da aynı şekilde Eloquent ORM'ye bağımlıdır. Şifre hatırlatıcı sistemini belirli bir ORM implementasyonuna bağlamak ne arzu edilen ne de gerekli olan bir şeydir. Bağımlılığı kırmak suretiyle, uygulamamızın şifre hatırlatıcı bileşenini etkilemeksizin, back-end depolama mekanizmamızı veya ORM'yi özgürce değiştirebiliriz. Tekrar ifade edeyim, SOLID ilkelerinden birini bozmakla, alıcı sınıfa uygulamanın geri kalanı hakkında çok fazla bilgi vermiş oluyoruz.

Bağımlılığı kırmak için, bir RemindableInterface oluşturalım. Aslında, böyle bir interface Laravel'de bulunmaktadır ve ön tanımlı olarak User modeli tarafından implemente edilmektedir:

interface RemindableInterface {
    public function getReminderEmail();
}

Interface oluşturulduktan sonra, modelimizde onu implemente edebiliriz:

class Contact extends Eloquent implements RemindableInterface {

    public function getReminderEmail()
    {
        return $this->email;
    }

}

Son olarak, PasswordReminder'da bu daha küçük, daha odaklı interface'e dayanabiliriz:

class PasswordReminder {

    public function remind(RemindableInterface $remindable, $view)
    {
        // Şifre hatırlatıcı e-postası gönder...
    }

}

Bu basit değişikliği yapmakla, şifre hatırlatıcı bileşeninden gereksiz bağımlılıkları çıkartmış olduk ve herhangi bir ORM'den bir sınıf kullanabilecek esnekliğe getirmiş olduk, tabii ki o sınıfın yeni RemindableInterfacei implemente etmesi şartıyla. Laravel'in şifre hatırlatıcı bileşeninin nasıl veritabanı ve ORM bilmez kaldığı tam olarak budur!

Bilgi Güçtür

Yine bir sınıfa uygulama implementasyon detayları hakkında çok fazla bilgi vermenin sakıncalarını keşfetmiş olduk. Bir sınıfa ne kadar bilgi verileceğine özen göstermek suretiyle, SOLID ilkelerinin hepsine uyabiliriz.

Sinan Eldem

Fullstack Web Developer

Laravel Framework ile PHP ve MySQL üzerine özel ders, danışmanlık ve web programcılığı hizmetleri veriyorum.

Danışmak istedikleriniz ile ilgili benimle irtibat kurabilirsiniz.

Benzer Yazılar

The Single Responsibility Principle (Tek Bir Sorumluluk İlkesi)

Tek Bir Sorumluluk İlkesi bir sınıfın bir ve yalnız bir değiştirme sebebi olmasını belirtir. Diğer bir deyişle, bir sınıfın kapsam ve sorumluluğu dar odaklı olmalıdır.

Liskov Substitution Principle (Liskov İkame İlkesi)

Bu ilke, bir soyutlamanın herhangi bir implementasyonunu o soyutlamayı kabul eden her yerde kullanabileceğinizi ifade eder ama bunu biraz basitleştirelim.

Dependency Inversion Principle (Bağımlılığı Tersine Çevirme İlkesi)

Bu son ilke Bağımlılığı Tersine Çevirme ilkesidir ve yüksek düzey kodun düşük düzey koda dayanmaması gerektiğini söyler.

Yorumlar