SOLID Prensipleri

SOLID Prensipleri (SOLID Principles)

SOLID prensipleri, Robert Cecil Martin (“Uncle Bob” – “Bob Amca”) tarafından ortaya atılan, nesne yönelimli programlamada (Object-Oriented Programming) yazılım tasarımının daha anlaşılır, esnek ve bakımını kolay hale getirmek için kullanılan beş önemli tasarım ilkesinin kısaltmasıdır. Bu kısaltma Michael Feathers tarafından tanımlanmıştır.

SOLID prensipleri şu şekildedir:

  • S –> Single Responsibility Principle (SRP): Tek Sorumluluk Prensibi
  • O –> Open / Closed Principle (OCP): Açık Kapalı Prensibi
  • L –> Liskov’s Substitution Principle (LSP): Liskov’un Yerine Geçme Prensibi
  • I -> Interface Segregation Principle (ISP) :Arayüz Ayrıştırma Prensibi
  • D -> Dependency Inversion Principle (DIP) :Bağımlılık Ters Çevirme Prensibi

 

Single Responsibility Principle (SRP)

Tek sorumluluk prensibi yani bir sınıfın yalnızca tek sorumluluğu ya da görevi olmalıdır. Bu presiple “Makarna Kod (Spagetti Code)” olarak tabir edilen kod tekrarı içeren, okunabilirliği zor ve tekrar düzeltilmesi zahmetli olan kod karmaşasının önüne geçmektir.

Örneğin Kategori ve Ürün sınıflarının olduğunu varsayalım. Kategori sınıfı yalnızca kategorilerin listelenmesi, yeni kategori eklenmesi, var olan kategorinin güncellenmesi ve silinmesi için gerekli metotları içerirken, Ürün sınıfı da ürünlerin listelenmesi, yeni ürün eklenmesi, kayıt ürünün güncellenmesi ve silinmesi gibi metotları içermelidir. Yani Kategori sınıfında ürünlerle ilgili ürünleri listeleme, ekleme, güncelleme veya silme gibi işlemler olmamalıdır. Aynı durum Ürün sınıfı için de geçerlidir.

Örnek amaçlı aşağıda verilen C# kodlarını inceleyebilirsiniz.


    public class CategoryRepository
    {

        public List<Category> GetCategories()
        {
            // ...
        }

        public Category GetCategoryById(int id)
        {
            // ...
        }

        public void CreateCategory(Category category)
        {
            // ...
        }

        public void UpdateCategory(Category category, int id)
        {
            // ...
        }

        public void DeleteCategory(int id)
        {
            // ...
        }
    }

    public class ProductRepository
    {

        public List<Product> GetProducts()
        {
            // ...
        }

        public Product GetProductById(int id)
        {
            // ...
        }

        public void InsertProduct(Product product)
        {
            // ...
        }

        public void UpdateProduct(Product product, int id)
        {
            // ...
        }

        public void DeleteProduct(int id)
        {
            // ...
        }
    }

 

Open / Closed Principle (OCP)

Açık kapalı prensibi, yazlımın gelişime açık ancak değişime kapalı olmasını gerektiğini belirtir. Yani var olan projeye yeni modüller ve işlevler eklenebilmelidir. Ancak bunu yaparken var olan kodlar üzerinde bir değişiklik yapılmadan gerçekleştirilmelidir.

Var olan metotlarda, if else koşul ifadeleri kullanılarak kodlar değiştirilmemelidir, bunun yerine duruma göre interface (arayüz) yada abstract class’lardan yararlanarak metotlar genişletilmeli ve yeni metotlar eklenmelidir. Kısaca buradaki amaç daha yönetilebilir kodların yazılması için ihtiyaç halinde var olan kodların genişletilmesidir. Daha fazla bilgi için nesne yönelimli programlamada inheritance – miras alma (kalıtım) konusunu araştırabilirsiniz.

 

Liskov’s Substitution Principle (LSP)

Liskov’un yerine koyma prensibi şunu söylemektedir: Her alt sınıf – türetilmiş sınıf (subclass/derived class), türetildiği üst sınıfın (base/parent class) tüm özelliklerini ve metotlarını aynı işlevleri gerçekleştirebilecek şekilde kullanabilmelidir. Tabi türetilmiş (alt) sınıflar ek olarak kendine ait yeni özellik ve metotlara sahip olabilir.

 

Interface Segregation Principle (ISP)

Nesnelerin ihtiyaç duymadıkları metotlar bulundukları interface’lere bağlı olmaya zorlanmamalıdır. Yapılması gereken nesnelerin ihtiyaç duyduğu metotlara göre interface’leri doğru parçalara ayırmak olmalıdır.

Örneğin cep telefonu için interface tanımlayacak olursak, “arama yap”, “mesaj gönder” ve “fotoğraf çek” metotları olduğunu varsayalım. Akıllı telefonlar bu işlevleri yerine getirecektir ancak tuşlu telefonlarda kamera olmadığını düşünürsek bu fonksiyon gereksiz olacaktır. Bu durumda ortak fonksiyonları içeren bir interface tanımlanabilir. Daha sonra tuşlu telefon ve akıllı telefon için ayrı ayrı interface’ler tanımlanır. Aşağıda örnek amaçlı yazılan basit kodları inceleyebilirsiniz.

    interface CepTelefonInterface
    {
        void aramaYap();
        void mesajGonder();
    }

    interface AkilliTelefonInterface : CepTelefonInterface
    {
        void fotografCek();
    }

    interface TusluTelefonInterface : CepTelefonInterface
    {
        // ...
    }

    class TusluTelefon : TusluTelefonInterface
    {
        public void aramaYap()
        {
            Console.WriteLine("Arama Yap Fonksiyonu");
        }

        public void mesajGonder()
        {
            Console.WriteLine("Mesaj Gönder Fonksiyonu");
        }
    }

    class AkilliTelefon : AkilliTelefonInterface
    {
        public void aramaYap()
        {
            Console.WriteLine("Arama Yap Fonksiyonu");
        }

        public void fotografCek()
        {
            Console.WriteLine("Fotoğraf Çek Fonksiyonu");
        }

        public void mesajGonder()
        {
            Console.WriteLine("Mesaj Gönder Fonksiyonu");
        }
    }

 

Dependency Inversion Principle (DIP)

Bağımlılığın ters çevrilmesi prensibine göre üst seviyeli modüller, alt seviyeli modüllere bağımlı olmamalıdır. Yani alt seviyeli sınıflarda yapılan değişiklikler üst seviyeli sınıfları etkilememelidir. Her ikisi de soyut (abstract) kavramlara bağlı olmalıdır. Kısaca yüksek seviyeli ve düşük seviyeli sınıflar arasında bir soyutlama katmanı oluşturabiliriz.

 

İlgili Yazılar