Teknoloji & Yapay Zeka

Mehmet Cem Yücel

Yazılım mimarisi, dağıtık sistemler ve yapay zeka odağında içerik üreten teknoloji meraklısı

Open/Closed Principle (OCP) Nedir? — SOLID'in İkinci Adımı

Not: İçeriğin orjinali ve alternatif dağıtımları hakkındaki bilgiler aşağıda paylaşılmıştır.

  • YouTube (orjinal içerik)
  • Blog (orjinal içerik temelli AI destekli)
  • Podcast (orjinal içeriğe ait ses)

“Software entities should be open for extension, but closed for modification.”
— Bertrand Meyer

Bu yazıda SOLID prensiplerinin ikinci adımı olan Open/Closed Principle (OCP) konusunu ele alıyoruz.
Kısaca: Kodunuzu değiştirmeden yeni davranışlar ekleyebilmek.


🎯 Hatırlatma: SRP ile Başlamıştık

Önceki yazıda Single Responsibility Principle (SRP)’yi incelemiş, bir e-ticaret sistemi örneği üzerinden kodumuzu tek sorumluluğa sahip sınıflara bölmüştük:

  • OrderProcessor siparişi yönetiyordu,
  • InvoiceService faturayı oluşturuyordu,
  • EmailService bildirim gönderiyordu,
  • ReportGenerator raporlamayı üstleniyordu.

Ancak bu hâl hâlâ mükemmel değil. Yeni bir iletişim kanalı (örneğin SMS veya Push Notification) eklemek istesek, bazı yerlerde kodu değiştirmemiz gerekir.
İşte OCP burada devreye giriyor.


🧱 OCP Nedir?

Open/Closed Principle, yazılım bileşenlerinin:

  • Yeni davranışlar eklemeye açık (open for extension),
  • Mevcut kodu değiştirmeye kapalı (closed for modification)

olması gerektiğini söyler.

Yani yeni bir gereksinim geldiğinde, var olan sınıfı değiştirmek yerine yeni bir sınıf eklemelisin.


⚠️ Sorun: Kodun Değişmesi Gerekiyor

class InvoiceService {
    private final EmailService emailService;

    public InvoiceService(EmailService emailService) {
        this.emailService = emailService;
    }

    public void sendInvoice(Order order) {
        emailService.send(order);
    }
}

Bu haliyle InvoiceService doğrudan EmailService’e bağımlı.
Yarın “SMS gönder” veya “Push Notification gönder” dersen, sendInvoice() metodunu değiştirmek zorundasın.

Kodun içine “if (sms) … else if (push)” gibi koşullar eklemeye başlarsan — OCP ihlal edilir.


✅ Çözüm: Ortak Bir Arayüz (Interface) ile Davranışı Ayırmak

Tüm bildirim servislerinin (email, sms, push) ortak bir davranışı var: Notify etmek.
Bu davranışı soyutlayarak Notifiable adında bir interface tanımlayabiliriz.

interface Notifiable {
    void notify(Order order);
}

Her iletişim kanalı bu interface’i uygular:

class EmailService implements Notifiable {
    public void notify(Order order) {
        System.out.println("Sending Email...");
    }
}

class SMSService implements Notifiable {
    public void notify(Order order) {
        System.out.println("Sending SMS...");
    }
}

class PushNotificationService implements Notifiable {
    public void notify(Order order) {
        System.out.println("Sending Push Notification...");
    }
}

Ve artık InvoiceService yalnızca bu interface’i bilir:

class InvoiceService {
    private final Notifiable notifier;

    public InvoiceService(Notifiable notifier) {
        this.notifier = notifier;
    }

    public void sendInvoice(Order order) {
        notifier.notify(order);
    }
}

Yeni bir bildirim yöntemi eklemek mi istiyorsun?
Yeni bir sınıf oluşturup Notifiable’ı implement etmen yeterli.

Kodun geri kalanına tek satır bile dokunmazsın.


⚙️ Daha Esnek Bir Adım: Strateji Patterni

OCP’nin en güçlü destekçisi Design Patternlerdir.
Burada Strategy Pattern kullanarak hangi bildirim stratejisinin çalışacağını runtime’da belirleyebilirsin.

public class NotificationStrategyFactory {
    public static Notifiable create(String strategyName) {
        try {
            Class<?> clazz = Class.forName(strategyName);
            if (!Notifiable.class.isAssignableFrom(clazz)) {
                throw new IllegalArgumentException("Invalid Notifiable type: " + strategyName);
            }
            return (Notifiable) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Ve main metodunda:

public static void main(String[] args) {
    String notifierClass = "com.technicaldebt.SMSService"; // runtime'da alınabilir
    Notifiable notifier = NotificationStrategyFactory.create(notifierClass);
    InvoiceService invoiceService = new InvoiceService(notifier);

    invoiceService.sendInvoice(new Order());
}

Artık hangi bildirimin gönderileceğini kodu değiştirmeden belirleyebilirsin.

Sadece runtime argümanını değiştir:
EmailServiceSMSServicePushNotificationService
ve sistem dinamik olarak genişler.


🧠 Tasarım Desenleriyle Bağlantısı

OCP, yazılım mimarisinde değişimden etkilenmeyen esneklik sağlar.
Design pattern’ler bu ilkenin pratik araçlarıdır:

  • Strategy Pattern: Dinamik davranış seçimi
  • Factory Pattern: Nesne yaratımında soyutlama
  • Decorator Pattern: Davranışı genişletme
  • Observer Pattern: Yeni tepkiler ekleme

Hepsi OCP’nin felsefesini destekler: Var olan kodu değiştirmeden genişletebilmek.


🎬 Sonuç ve Devam

Bu yazıda Open/Closed Principle (OCP)’yi inceledik.
Yeni davranışları mevcut sistemi bozmadan nasıl ekleyebileceğimizi gördük.

Bir sonraki yazıda SOLID’in üçüncü adımı olan Liskov Substitution Principle (LSP) üzerine konuşacağız.


🎥 Videoyu izlemek istersen:

Kopyala ve Paylaş: Open/Closed Principle (OCP) Nedir? — SOLID'i...




Bu başlıklar ilginizi çekebilir

comments powered by Disqus