Hızlı tempolu yazılım geliştirme dünyasında, çalışan kod yazmak sadece savaşın yarısıdır. Diğer yarısı, bakımı, genişletilmesi ve ölçeklendirilmesi kolay kod yazmaktır. İşte SOLID ilkeleri burada devreye girer. Robert C. Martin tarafından ortaya atılan bu beş tasarım ilkesi, gereksinimler değişse bile sağlam kalan nesne yönelimli kod yazmak için bir hile kartı görevi görür. Orta düzeyden ileri düzey geliştiriciler için SOLID'i ustalaşmak sadece kurallara uymakla ilgili değildir; esnekliği ve netliği önceliklendiren bir zihniyet benimsemekle ilgilidir.
1. Tek Sorumluluk İlkesi (SRP)
Bir sınıfın değişmesi için tek bir ve yalnızca tek bir nedeni olmalıdır. Bir sınıf hem iş mantığını hem de veri kalıcılığını ele alıyorsa, SRP'yi ihlal eder. Endişelerin ayrılması, sistemin bir yönündeki değişikliklerin diğerini istemeden bozmasını önler.
// Kötü: Tek sınıfın birden fazla iş yapması
public class User {
public void save() { /* veritabanı mantığı */ }
public void sendEmail() { /* e-posta mantığı */ }
}
// İyi: Sorumlulukların ayrılması
public class UserRepository {
public void save(User user) { /* veritabanı mantığı */ }
}
public class EmailService {
public void sendWelcome(User user) { /* e-posta mantığı */ }
}
2. Açık/Kapalı İlkesi (OCP)
Yazılım varlıkları genişletilmeye açık, ancak modifikasyona kapalı olmalıdır. Yeni özellikler eklemek için mevcut kodu değiştirmek yerine, onu genişletmelisiniz. Bu genellikle soyutlama ve polimorfizm yoluyla sağlanır.
// Kötü: Mevcut kodun değiştirilmesi
public class Discount {
public double calculate(Invoice invoice) {
if (invoice.getType() == "VIP") return invoice.getTotal() * 0.9;
// Risk almadan yeni tipler eklemek zordur
}
}
// İyi: Strateji deseni ile genişletme
public interface DiscountStrategy {
double calculate(Invoice invoice);
}
public class VipDiscount implements DiscountStrategy {
public double calculate(Invoice invoice) {
return invoice.getTotal() * 0.9;
}
}
3. Liskov Yerine Koyma İlkesi (LSP)
Üst sınıf nesneleri, uygulamayı bozmadan alt sınıf nesneleriyle değiştirilebilmelidir. Bu, mirasın doğru kullanıldığını ve alt tiplerin gerçekten üst tiplerinin davranışları olduğunu garanti eder.
Örneğin, bir Square (Kare), bir Rectangle (Dikdörtgen)den miras almamalıdır çünkü bir karenin genişliğini ayarlamak, bir dikdörtgen için olduğu gibi aynı anlamda mantıklı değildir ve davranışsal beklentileri ihlal eder.
4. Arayüz Ayrıştırma İlkesi (ISP)
Müşteriler, kullanmadıkları arayüzlere bağımlı olmaya zorlanmamalıdır. Genel amaçlı tek bir arayüzden çok, birden fazla spesifik arayüze sahip olmak daha iyidir. Bu, bağlanmayı azaltır ve kodu anlamayı kolaylaştırır.
// Kötü: Büyük arayüz
public interface Worker {
void work();
void eat();
void sleep();
}
// İyi: Ayrıştırılmış arayüzler
public interface Workable {
void work();
}
public interface Eatable {
void eat();
}
5. Bağımlılık Tersine Çevirme İlkesi (DIP)
Yüksek düzey modüller, düşük düzey modüllere bağımlı olmamalıdır. Her ikisi de soyutlamalara bağımlı olmalıdır. Bu, gevşek bağlanmayı teşvik eder ve bağımlılıkların taklit edilmesine veya değiştirilmesine izin vererek test etmeyi kolaylaştırır.
// Kötü: Doğrudan bağımlılık
public class OrderService {
private MySqlDatabase db = new MySqlDatabase();
}
// İyi: Soyutlamaya bağımlılık
public class OrderService {
private Database db;
public OrderService(Database db) {
this.db = db;
}
}
Sonuç
SOLID ilkelerini uygulamak, her kod satırında bunlara katı bir şekilde bağlı olmanız gerektiği anlamına gelmez. Bunun yerine, tasarımınızın kırılganlaştığını tespit etmek için bunları kılavuzlar olarak kullanın. Tek Sorumluluk, Açık/Kapalı, Liskov Yerine Koyma, Arayüz Ayrıştırma ve Bağımlılık Tersine Çevirme'ye odaklanarak, sadece bugün işlevsel olan değil, aynı zamanda yarının zorluklarına da uyum sağlayabilen yazılımlar geliştirebilirsiniz.