Single Responsibility Principle



3 dakikalık okuma
December 16, 2018

Adından da anlaşılacağı üzere “tek bir sorumluluğa sahip olma” prensibi. Eskiden ben şöyle kod yazardım: “Tüm işime yarayan metodları tek bir dosyada bir sınıf altında toplardım. Kendimce bu sınıfı kullanarak uygulamalarımı geliştirirdim. ” Aslında bu yöntem sakat bir yöntem olup bu prensiple çelişmektedir. Çünkü bu prensibe göre bir sınıf sadece bir tane sorumluluğa sahip olmak zorundadır. Bob amcanın tabiriyle “Bir sınıfı değiştirmek için bir tek nedenin olmalı.” Böylece kodun bakımı, okunabilirliği ve geliştirmesi daha kolay olacaktır.

Örneklendirerek anlatıma devam edelim:

Bir okul kayıt programı geliştiriyor olduğumuzu farz edelim. “OgrenciIslemleri” adında sınıfımız olsun ve bu sınıf sadece öğrenci kaydetme, silme, güncelleme işini yapmış olsun.

Taslağı şöyle hazırlayalım:

class OgrenciIslemleri {

    public function kaydet() {
        return “öğrenci bilgisi kaydedildi”
    }

    public function sil() {
        return “öğrenci bilgisi silindi”
    }

    public function guncelle() {
        return “öğrenci bilgisi guncellendi.”
    }
}

Yukarıdaki kaydet metodu içine aşağıdaki gibi veritabanı kodlarını döşeyeceğimizi sanmayın. Döşemeyeceğiz. Ben yine aşağıda yazıp göstereyim:

//kötü tasarımlı bir sınıf. Sınıfta birden fazla sorumluluk var.

class OgrenciIslemleri {

const servername = "localhost";
const username = “isim”;
const password = “sifre”;
const dbname = "myDB";


    public function db_kaydet() {


    $conn = new mysqli(self::servername, self::username, self::password, self::dbname);

    if ($conn->connect_error) {
        die("Connection failed: " . $conn->connect_error);
    } 

    $sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES (‘Remzi’, ’Sami’, ‘deneme@deneme.com’)";

  if ($conn->query($sql) === TRUE) {
        echo “Yeni mesaj oluşturuldu“;
    } else {
        echo "Error: " . $sql . "<br>" . $conn->error;
    }
    $conn->close();
}

    public function kaydet($post) {
        return $this->db_kaydet($post)
    }

    public function sil() {
        return “öğrenci bilgisi silindi”
    }

    public function guncelle() {
        return “öğrenci bilgisi guncellendi.”
    }

}

Çünkü burada birden fazla sorumluluk var. Bir defa veritabanı bağlantısı ve veritabanı şifrelerini girme işi var. Veritabanına kayıt ve bunun doğruluğunu kontrol işi var. Bu da ayrı bir sorumluluk. Peki ne yapacağız. Ayrı bir sınıfta sadece veritabanı işlemlerinin bulunduğu kaydetme, silme gibi metodların olduğu bir yapımızın olması gerek. Çünkü “OgrenciIslemleri” sınıfında sadece bir sorumluluk olmalı. O da öğrenci kaydetme, öğrenci silme ve öğrenci güncelleme işidir. İleride veritabanımızı MySQL’den MSSQL yaparsak bu “OgrenciIslemleri” sınıfına hiç dokunmamamız gerekir.

O zaman kodlarımızı şöyle düzenleyelim:

use DB; 
use Mail;

class OgrenciIslemleri {

    public $db;

   public function __construct(dbAdaptor $adaptor)
    {
        $this->db = $adaptor;
    }

    public function kaydet(Array $post) {

        $kaydedildi = $this->db->save($post);
        return $kaydedildi;
    }

    public function sil(Array $post) {
        return $this->db->del$post);
    }

    public function duzenle(Array $post) {
        return $this->db->update($post);
    }
}

Yukarıdaki sınıfımızı şöyle kullandığımızı farz edersek:

veritabani = new MySQLAdapter();

$og = new OgrenciIslemleri(veritabani);

$og->kaydet($_POST);

Şimdi SRP(Single Responsibility Principle) ile kodumuzun çelişip çelişmediğini şöyle anlayabiliriz:

  1. Veritabanımızı MySQL’den MSSQL yaparsak “OgrenciIslemleri” sınıfında değişiklik yapmalı mıyız?

Cevap: Hayır.Çünkü bu ayrı bir sorumluluk ve sınıfı da ayrı olması gerekir. Dikkat ederseniz veritabanı adaptörünü dışarıdan enjekte ediyoruz. Yani veritabanı işlemleri “OgrenciIslemleri” sınıfında değil. Adaptörü MSSQLAdapter yaparsak hiç bir şey yapmadan artık kayıtlarımız MSSQL veritabanına olacaktır.

Yukarıdaki tüm sorunun cevabı hayırsa SRP prensibi ile çelişmeyen bir sınıf yazdığımızı söyleyebiliriz.

Yukarıdaki örnek biraz farklı gelebilir; ama konunun özünü anlatmak için böyle hayali bir kurgudan giderek özü vermek istedim. Dikkat ettiyseniz injection hadisesi için Interface vs. gibi hadiseleri de kullanmama rağmen açıklamadım. Çünkü sonraki prensiplerde giriş yapacağız.


Etiketler: