SOLID İlkeleri: Kod Kalitenizi Artırmanın Anahtarı

Mehmet Akgül
3 min readJul 27, 2023

--

Bir yazılım geliştirici olarak, kaliteli kod yazmanın önemini anlamak ve uygulamak hayati öneme sahiptir. Yüksek kaliteli kod, sadece daha az hata içermez, aynı zamanda daha anlaşılır, sürdürülebilir ve genişletilebilir olmalıdır. Bu, nesne yönelimli programlamanın (OOP) SOLID ilkeleri ile başarılabilir.

1. Tek Sorumluluk İlkesi (Single Responsibility Principle)

Bu ilke, her sınıfın sadece bir işlevi olması gerektiğini söyler. Bir sınıfın birden çok işlevi olursa, bu sınıfı anlamak, test etmek ve hataları düzeltmek daha zor olabilir.

Örneğin, aşağıdaki Order sınıfı hem sipariş tutarını hesaplamaktan hem de veritabanına kaydetmekten sorumludur, bu yüzden iki sorumluluğu vardır:

public class Order {
public void calculateTotalSum() { /*...*/ }
public void save() { /*...*/ }
}

Yukarıdaki durumda, hesaplama ve veritabanı işlemlerini birbirinden ayırmak daha mantıklıdır. Böylece, her sınıf kendi sorumluluğunu yerine getirir:

public class Order {
public void calculateTotalSum() { /*...*/ }
}

public class Database {
public void save(Order order) { /*...*/ }
}

2. Açık-Kapalı İlkesi (Open-Closed Principle)

Bu ilke, mevcut bir sınıfın yeni davranışlara açık, ancak mevcut davranışlarda kapalı olması gerektiğini söyler. Yani, bir sınıfın davranışını genişletmek isterseniz, mevcut kodunu değiştirmeden yeni bir sınıf ekleyebilmelisiniz.

🚀 Detaylı bir makaleyi burada bulabilirsiniz 🚀

Aşağıdaki kodda, bir dikdörtgenin alanını hesaplama işlemi var. Ancak yeni bir şekil türü eklemek istediğimizde AreaCalculator sınıfını değiştirmemiz gerekecek:

public class Rectangle {
public int width, height;
}

public class AreaCalculator {
public int calculateRectangleArea(Rectangle rectangle) {
return rectangle.width * rectangle.height;
}
}

Bu durumu düzeltmek için, her şeklin kendi alanını hesaplama metodu olacak şekilde, bir Shape arayüzü oluşturabiliriz. Böylece, yeni bir şekil eklediğimizde, mevcut kodda hiçbir değişiklik yapmamız gerekmez:

public interface Shape {
int calculateArea();
}

public class Rectangle implements Shape {
public int width, height;

public int calculateArea() {
return width * height;
}
}

public class AreaCalculator {
public int calculateShapeArea(Shape shape) {
return shape.calculateArea();
}
}

3. Liskov Yer Değiştirme İlkesi (Liskov Substitution Principle)

Bu ilke, bir programın doğruluğunu bozmadan, bir sınıfın örneklerinin alt sınıfının örnekleri ile değiştirilebilir olması gerektiğini ifade eder. Diğer bir deyişle, bir alt sınıf, onu genişleten süper sınıfın yerini her zaman alabilmelidir.

public class Bird {
public void fly() { /*...*/ }
}

public class Ostrich extends Bird { /*...*/ }

Yukarıdaki örnekte, tüm kuşlar uçabilir mantığıyla Bird sınıfında bir fly() metodu bulunmaktadır. Ancak, devekuşları (Ostrich) uçamazlar. Bu durum Liskov Yer Değiştirme İlkesini ihlal eder. Bu durumu düzeltmek için:

public class Bird { /*...*/ }

public class FlyingBird extends Bird {
public void fly() { /*...*/ }
}

public class Ostrich extends Bird { /*...*/ }

4. Arayüz Segregasyon İlkesi (Interface Segregation Principle)

Bu ilke, müşterilerin kullanmayacağı metotları içeren “şişman” arayüzlerden kaçınılması gerektiğini belirtir. Bir sınıfın, kendisi tarafından kullanılmayan bir metodu içeren bir arayüzü uygulaması gerektiğinde, bu sınıf gereksiz bağımlılıklara sahip olur.

interface Worker {
public void work();
public void eat();
}

Yukarıdaki örnekte, Worker arayüzü hem work() hem de eat() metodlarını içerir. Ancak bazı işçiler (örneğin robotlar) yemek yemez. Bu durumu düzeltmek için:

interface Workable {
public void work();
}

interface Eatable {
public void eat();
}

class HumanWorker implements Workable, Eatable {
public void work() { /*...*/ }
public void eat() { /*...*/ }
}

class RobotWorker implements Workable {
public void work() { /*...*/ }
}

5. Bağımlılık Ters Çevirme İlkesi (Dependency Inversion Principle)

Bu ilke, üst düzey modüllerin düşük düzey modüllere bağımlı olmaması gerektiğini belirtir. İki modül arasında bir bağımlılık olduğunda, bu bağımlılık soyutlamalar üzerinden olmalıdır.

class LightBulb {
public void turnOn() { /*...*/ }
public void turnOff() { /*...*/ }
}

class ElectricPowerSwitch {
public LightBulb lightBulb;

public ElectricPowerSwitch(LightBulb lightBulb) {
this.lightBulb = lightBulb;
}

public void press() { /*...*/ }
}

Yukarıdaki örnekte, ElectricPowerSwitch sınıfı LightBulb sınıfına bağımlıdır. Bu durumu düzeltmek için:

interface Switchable {
void turnOn();
void turnOff();
}

class LightBulb implements Switchable {
public void turnOn() { /*...*/ }
public void turnOff() { /*...*/ }
}

class ElectricPowerSwitch {
public Switchable switchable;

public ElectricPowerSwitch(Switchable switchable) {
this.switchable = switchable;
}

public void press() { /*...*/ }
}

Bu beş SOLID ilkesi, daha esnek, anlaşılır ve genişletilebilir bir sistem oluşturmanın anahtarını sunar. Daha sağlıklı ve kaliteli bir kod yapısına sahip olmak isteyen her yazılım geliştiricinin bu prensipleri benimsemesi gerekir.

#SOLID #OOP #Java #SoftwareDevelopment #BestPractices

--

--