12.01.2024

9

Like

349

Views

SOLID Prensipleri

Merhabalar,

Bugün sizlere senior yazılımcıların bildiği, junior yazılımcıların çok fazla denk gelmediği (mülakatlar hariç) SOLID prensipleri hakkında bilgilendirmek istiyorum.

Nedir ulan bu! SOLID prensipleri.

Bu prensipler, Robert C. Martin tarafından kaleme alınmış ve 5 maddeden oluşmaktadır. Yukarıdaki görseli inceledikten sonra, SOLID prensiplerinin nesne yönelimli programlamanın temel ilkeleriyle doğrudan bağlantılı olduğunu göreceksiniz.

Peki ya biz SOLID prensiplerini OOP’nin 5 maddesi olarak tanımlayabilir miyiz? Cevabımız evet…

SOLID neden bu kadar önemli? Bize ne fayda sağlayacak?

Yazdığımız kod temiz olacak, Yazdığımız kod anlaşılır olacak, Bakımı kolay olacak, Geliştirmesi kolay olacak…

Bu yüzden SOLID’i anlamak ve kullanmak çok önemli.

İlk maddemiz Single Responsibility Principle (Tek Sorumluluk İlkesi).

Bu ilkede bizden istenen yazdığınız sınıf İsveç çakısı gibi her işi yapmasın. Sınıfın veya modülün yalnızca bir sorumluluğu olması gerektiğini belirtir. Bu ilkeye göre, bir sınıfın veya modülün yalnızca bir nedeni olmalıdır değişiklik yapması veya değişmesi gereken tek bir neden olmalıdır.

SRP’nin temel amacı, kodun bakımını kolaylaştırmak, anlaşılabilirliği artırmak ve daha az hata üretmek için yazılımın parçalarını daha küçük ve daha özgün parçalara bölmektir. Bu ilkeyi takip etmek, kodun daha temiz, daha düzenli ve daha esnek olmasını sağlar. Aşağıda bir Java örneğinde kullanımına göz atabiliriz.

İki ayrı sınıfımız var: Kullanici ve KullaniciYonetici.

Kullanicisınıfı, yalnızca kullanıcı bilgilerini temsil eder. Kullanıcı adı ve şifre gibi temel kullanıcı bilgilerini içerir. Bu sınıf, kullanıcı verilerini sadece saklamakla sorumludur ve başka bir işlevi yoktur.

KullaniciIslemsınıfı ise kullanıcı yönetimi ile ilgili işlemleri gerçekleştirir. Bu sınıf, kullanıcıları eklemek veya silmek gibi kullanıcı yönetimi işlemlerini içerir. Aynı zamanda kullanıcıları listelemek veya düzenlemek gibi işlemler de burada gerçekleştirilebilir.

Bu şekilde, her iki sınıfın da ayrı ve net bir sorumluluğu vardır. Kullanici sınıfı sadece verileri saklar, KullaniciIslemsınıfı ise bu verileri işler. Bu sayede kodunuz daha anlaşılır, bakımı kolay ve değişikliklere daha açık hale gelir. Bu da Single Responsibility Prensibi’nin kod kalitesini artırıcı bir rol oynadığını gösterir.

İkinci maddemiz Open-Close (Açık-Kapalılık İlkesi).

Bu ilke bize sınıfın gelişime açık fakat değişime kapalı olduğunu gösterir. Yani bir sınıfın veya bir fonksiyonun hali hazırdaki durumunun korunuyor olması gerekiyor ve bu durum korunarak hiçbir değişiklik yapmadan sınıfın veya fonksiyonun geliştirilebiliyor olması gerekiyor. Peki ya biz bunu nasıl yapacağız? Yukarıdaki örneğimizi hatırlıyorsunuz. Onun üzerinden anlatmaya devam edelim.

Mevcut Kullanici sınıfı değiştirilmeden, yeni kullanıcı işlemleri eklemek veya mevcutları değiştirmek için KullaniciIslem arayüzünü uygulayan sınıflar oluşturabiliriz. Bu sayede kod, yeni işlevselliği eklemek veya mevcut işlevselliği değiştirmek için kapalıdır (değiştirilmesi gerekmez) ve açıktır (yeni işlevselliği eklemek kolaydır).

Üçüncü maddemiz Liskov Subtitution (Liskov İkame İlkesi).

Bu ilke bize şunu söylüyor. “Sen bir sınıfa bir method yazdıysan ve bu sınıftan başka sınıflar miras alıyorsa, bu miras alan sınıflar mirası kullanmıyorsa bu özelliği opsiyonel yap.” Bunu sözel olarak şöyle açıklayalım. Bizim “kuşlar” ve “tavuk” adında sınıfımız olsun. “tavuk” sınıfımız “kuşlar” sınıfından miras alıyor ve “kuşlar” sınıfının içerisinde “uç” adında bir method var. Biz biliyoruz ki tavuklar uçamaz, değil mi? Bu durumda “tavuk” sınıfı aldığı methodu opsiyonel şekilde kullanması gerekiyor. İşte buna Liskov Subtitution diyoruz. Örnek üzerinden kodumuzu geliştirelim.

Kullanici sınıfı, kullanıcı bilgilerini temsil eden bir yapı içeriyor ve değiştirilmeyecek bir şekilde tasarlandı.

KullaniciIslem adında bir arayüz (interface) tanımladık. Bu arayüz, kullanıcı işlemlerini (kullanıcı ekleme ve silme) tanımlayan metotları içerir. Bu arayüzü, türetilmiş sınıfların uygulaması gereken bir şablona dönüştürdük.

KullaniciYonetici sınıfını tanımladık ve KullaniciIslem arayüzünü uyguladık. Bu sınıf, kullanıcı işlemlerini gerçekleştiriyor ve temel sınıf olan Kullanici ile çalışıyor. Burada, Liskov Substitution Prensibi'ne uyan bir ilişki kurduk çünkü KullaniciYoneticiKullaniciIslem arayüzünü başarılı bir şekilde uyguluyor ve temel sınıfın yerine kullanılabilir.

Son olarak, KullaniciYoneticiAlt adında yeni bir sınıf oluşturduk ve bu sınıfı KullaniciYonetici sınıfından türettik. KullaniciYoneticiAlt sınıfı, temel sınıf olan KullaniciYonetici'nin davranışını değiştirmemiş, yalnızca yeni bir işlev olan kullaniciGuncelle metodunu eklemiştir. Bu, Liskov Substitution Prensibi'ne uygun bir şekilde gerçekleştirilmiştir çünkü KullaniciYoneticiAlt, temel sınıfın yerine geçebilir ve aynı arayüzü uygular.

Dördüncü maddemiz Interface Segregation Principle (Arayüz Ayırma İlkesi).

Bu prensip bize şunu söylüyor, yine aynı şekilde İsveç çakısı gibi birçok işi yapan bir interface kullanma, interfaceleri olabildiğince böl. Kendi amacına hizmet eden interface olarak kullan. Bir interface bir sınıftan miras aldığında bütün güçleri kullanıyor olsun. İşimize yaramayacak olan güçlerden kurtulalım. Daha önceki görsellerde bunu zaten kullanmıştık. Tekrar bir göz atalım ve geliştirelim.

Her interface’in yalnızca belirli bir kullanıcı işlem türünü temsil ettiği ve sınıfların yalnızca ihtiyaç duydukları interface’leri uyguladığı bir tasarımı yansıtır. Bu, Interface Segregation Principle’ını uygulamanın bir yoludur. Her sınıf, yalnızca kendi gereksinimlerine uygun olan interface’leri uygular, böylece gereksiz metotların sınıflar üzerindeki yükü azaltılmış olur.

Son ve beşinci maddemiz Dependency Inversion Principle (Bağımlılığı Tersine Çevirme İlkesi).

Bir alt sınıf içerisinde doğabilecek değişiklik bir üst sınıfı etkilemesin. Bunu örneklerle daha iyi kavrayabileceğimizi düşündüğüm için hemen örneğimizi geliştirerek devam edelim.

Yüksek Seviyeli Modül (High-Level Module): Kullanıcıların doğrulama işlemlerini gerçekleştirdiği yüksek seviyeli bir modül düşünelim.

Düşük Seviyeli Modül (Low-Level Module): Doğrulama işlemini gerçekleştiren düşük seviyeli bir modül düşünelim.

KullaniciServisi yüksek seviyeli bir modül ve Dogrulama düşük seviyeli bir modüldür. KullaniciServisi, doğrulama işleminin nasıl yapılacağına karışmaz ve sadece bir Dogrulama arayüzüne bağımlıdır. Bu şekilde, DIP prensibine uygun bir tasarım elde edilmiştir.

Dependency Inversion Principle, yüksek seviyeli modüllerin düşük seviyeli modüllere doğrudan bağımlı olmamasını, soyutlamalara (arayüzler veya abstract sınıflar) bağımlı olmalarını ve bu soyutlamaların bağımlılıkların tersine döndürülmesini önerir. Bu sayede yazılımın esnekliği ve bakımı artar, yeni özellikler eklemek veya mevcut kodu değiştirmek daha kolay hale gelir.

Bu sayede bütün maddeleri ele almış olduk. Umarım sizlere yardımcı olmuştur. Buraya kadar okuyan veya göz atan herkese iyi çalışmalar dilerim :)

Yazılım Mühendisliği 101
Yazılım, Internet, Kodlama ve Konseptleri

Comments

You need to log in to be able to comment!

Batuhan Şahin

Düzce Üniversitesi Bilgisayar Mühendisliği Bölümünden 3.00 ortalama ile mezun oldum. Aktif iş arayışım sürmektedir. Bu dönemde ağırlıklı olarak Java eğitimleri ile kendimi geliştirmekteyim.

Location

İstanbul, TR

Education

Bilgisayar Mühendisliği - Düzce Üniversitesi

Job Experience

Stajyer - Tübitak Bilgem

© 2021 Patika Dev

facebook
twitter
instagram
youtube
linkedin