Yazılım Geliştirme
SOLID Prensipleri Nedir? C# Örnekleriyle Basit Anlatım
Bu yazıda SOLID prensiplerini sade bir dille ve C# örnekleri üzerinden ele alıyorum. Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation ve Dependency Inversion prensiplerinin ne işe yaradığını ve nasıl uygulanabileceğini örneklerle inceliyoruz

1. SRP – Single Responsibility Principle
Single responsibility Principle şunu söyler: her sınıfın tek
bir sorumluluğu olmalıdır. Yani bir class birden fazla farklı işi yapmamalıdır.
Örneğin: UserService sınıfını düşünelim. Eğer ki bu sınıf
hem:
·
Kullanıcı kaydediyor
·
Email gönderiyor
·
Dosyaya yazıyor
İse çok fazla işi aynı sınıfa toplamış oluruz. Bu durum SRP’ye
aykırı bir durumdur.
OCP – Open/Closed Principle
OCP şunu söyler: kod geliştirmeye açık değiştirmeye kapalı
olmalıdır. Buradaki amaç şudur: “Yeni özellik istediğinde mevcut çalışan kodu
sürekli değiştirmek zorunda kalmamalıyız.”
Yani yeni bir özellik eklemek istediğim zaman, çalışan eski
kodu değiştirmemeliyim
Buradaki “Open” = yeni özellik eklemeye açık anlamına gelirken
“Closed” = mevcut kodu değiştirmeye kapalı anlamına gelir.
Örnek:
Diyelim ki bir ödeme sistemimiz var.

Şuanda burada 2 farklı ödeme türü var: CreditCard ve Cash.
Biz buna sonradan PayPal eklemek istediğimizde gidip mevcut
PaymentService Sınıfına girip bunu ekleriz
Sonra havale ile ödeme geldiğinde tekrar gider eski sınıfa
ekleme yaparız

Yani burada her seferinde PaymentService sınıfını
değiştiriyoruz. İşte open/closed buna karşı çıkıyor.
Open/Closed prensibine göre nasıl yapmamız gerekir?
1.
Önce interface oluştururuz

Kredi Kartı eklediğimizde

Nakit geldiğinde

Yani burada sonradan yeni bir özellik geldiğinde gidip yeni sınıf oluşturup yaparız. Bu şekilde de eski kodumuzu değiştirmeyiz
L – Liskov Substition Principle
LSP, ortak bir referanstan türeyen nesnelerin hiçbir şeyi
bozulmadan birbirleriyle değiştirilebilmesi gerektiğini yani birbirlerinin
yerine geçebilmesi gerektiğini öneren bir prensiptir. Yani hiçbir alt sınıf,
uygulamış olduğu base class’ın metotlarını ihlal etmemelidir. Yani hiçbir metot
boş kalmamalı veya boş kalmasın diye Not Implemented Exception gibi hatalar
döndürmemelidir.
Özet: LSP: Bir base sınıf veya interface hangi davranışı
vaat ediyorsa, ondan türeyen tüm sınıflar da bu davranışı düzgün şekilde
gerçekleştirebilmelidir. Örneğin base yapıda Pay() metodu varsa, alt sınıflar
bu ödeme işlemini gerçekten yapabilmelidir. Eğer bir ödeme türü Pay() işlemini
desteklemiyorsa, o yapıdan türememelidir.
Örnek (LSP İHLAL ÖRNEĞİ)

bu LSP ye uymaz. çünkü ben c# a diyorum ki senin Pay
şeklinde metotun var ve bu metot içerisinde ödeme başarılı şekilde
yapılabilecek. Fakat ben taksit seçeneğini seçtiğimde olmuyor. Bu LSP ye
aykırıdır
Örnek 2 (LSP Örneği)

Bu yapı LSP’ye uygundur çünkü IPayment interface’ini
implement eden sınıflar Pay() davranışını gerçekten destekler. Alt sınıflar,
üst tipin yerine kullanıldığında programın beklenen davranışını bozmaz.
I – Interface Segregation Principle
Bir interface’i implement eden sınıf, kullanmayacağı
metotları yazmak zorunda kalmamalıdır.
ISP ye Aykırı bir örnek

Burada hayvanlar iş yapmaz. Bu yüzden bu sınıfı implement
etmemelidir. Yani work sınıfım animal class’ında boş kaldı. Bu durum ISP’ye
aykırıdır
ISP Örnek

Doğru kullanım bu şekilde olmalıdır. Bu kullanımda herhangi
boş bir sınıf yok yani kullanılmayan bir sınıf yok.
Dependency Inversion Principle
Dependency Inversion Principle Nedir?
Bir class, başka bir class’a doğrudan bağlı olmamalıdır. Bunun
yerine interface gibi soyut yapıya bağlı olmalıdır. Mesela bir OrderService
sınıfımız olsun ve bu sınıf ödeme almak istiyor olsun. Eğer OrderService direkt
olarak CreditCardPayment sınıfını oluşturuyorsa yani
var payment = new CreditCardPayment();
OrderService, artık CreditCardPayment sınıfına tight
coupling yani sıkı sıkıya bağımlı olur. DIP der ki: OrderService sınıfımız,
CreditCardPayment’a bağlı değil IPayment şeklinde bir interface e bağlı olsun.
Neden Kullanılır?
DIP kullanılmazsa, yarın kredi kartı yerine CashPayment,
BankTransferPayment geldiğinde, ana sınıfımın kodunu sürekli değiştirmem
gerekir.
DIP kullanıldığında ana sınıfımı değiştirmem sadece
dışarıdan hangi servisi vereceğime karar veririm
Dependency Inversion Principle Olmadan Örnek

Yarın diğer gün nakit ödeme istediğimizde:

Dependency Inversion Principle Kullanarak Örnek

Yani Dependency Inversion Prensibi, bir sınıfın concrete
sınıflara değil onların abstraction’larına bağlı olması gerektiğini önerir. Böylece
o sınıf herhangi bir somut sınıfa bağımlı olmayacak