OCP (Açık/Kapalı Prensibi), SOLID'in ikinci prensibidir ve şunu belirtir: yazılım varlıkları genişlemeye açık ancak değişikliğe kapalı olmalıdır. Bertrand Meyer tarafından 1988'de formüle edilen bu prensip, mevcut kodu değiştirmeden yeni işlevsellik eklemeye olanak tanır. Robert Martin'in kitabı Clean Architecture (2017)'ye göre, açıklık prensibi soyutlamalar ve çok biçimlilik yoluyla uygulanır ve gerileme hataları riskini en aza indirir.
Anahtar Noktalar
OCP (Açık/Kapalı Prensibi) — genişlemeye açıklık ve değişikliğe kapalılık prensibi. Sınıflar, modüller ve işlevler, kaynak kodlarını değiştirmeden yeni davranışlar eklenebilecek şekilde tasarlanmalıdır. Genişletme, kalıtım, kompozisyon veya arayüz uygulamalarının değiştirilmesi yoluyla elde edilir.
Bertrand Meyer, Object-Oriented Software Construction (1988) kitabında OCP'yi ilk kez kalıtım yoluyla tanımladı: temel sınıf değişmeden kalırken, alt sınıflar onun davranışını genişletir. Robert Martin tarafından önerilen OCP'nin modern yorumu, çok biçimlilik ve arayüzlere dayanır: kalıtım yerine soyut sözleşmeler kullanılır.
Yaklaşımlar arasındaki fark önemlidir. Kalıtım, temel ve türetilmiş sınıflar arasında güçlü bir bağlılık oluşturur. Arayüzler ve kompozisyon esneklik sağlar: uygulama, istemci kodu değiştirilmeden değiştirilebilir. Modern OCP, kalıtımla değil, soyutlamayla ilgilidir.
Çok biçimli OCP, bir sözleşme tanımlamak için soyut sınıflar veya arayüzler kullanır. İstemci kodu, somut uygulamayı bilmeden soyutlamayla çalışır. Yeni işlevsellik, aynı arayüzü uygulayan yeni bir sınıf oluşturularak eklenir — mevcut kodda tek bir değişiklik olmadan. Bu, sistemi değişikliğe karşı dirençli ve genişletme için öngörülebilir kılar.
Mobil geliştirmede bu yaklaşım her yerde mevcuttur: Strategy kalıbı, ortak bir arayüz aracılığıyla algoritmaların (görüntü sıkıştırma, önbellekleme, kimlik doğrulama) değiştirilmesine olanak tanır. Yeni bir strateji eklemek, onu kullanan kodu değiştirmeyi gerektirmez.
OCP'yi uygulamak, değişken davranışı bir soyutlamaya ayırmakla başlar. Kodda bir switch yapısı veya bir nesnenin türünü kontrol eden bir if-else zinciri varsa — bu OCP'yi uygulamak için bir işarettir. Her koşullu dal, genişletme sırasında potansiyel olarak yeni bir dal eklenmesini gerektirir.
OCP altındaki yeniden düzenleme süreci üç adım içerir: değişken yönü (genişletilebilecek olanı) belirleyin, onu bir arayüze veya soyut sınıfa ayırın, istemci kodunu somut sınıf yerine soyutlamayla çalışacak şekilde yeniden yazın. Bundan sonra, yeni işlevsellik istemci değiştirilmeden eklenir.
Önemli bir açıklama: değişikliğe kapalılık mutlak değildir. Bir gereksinim değişikliği soyutlamanın kendisini veya sözleşmeyi etkiliyorsa — değişiklik kaçınılmazdır. OCP, sözleşmelerde değil, uygulamalardaki değişikliklere karşı korur. İyi tasarım, sözleşmelerin istikrarlı ve uygulamaların değişken olduğunu varsayar.
Bir mimarinin OCP uyumluluğunu değerlendirirken, genişletme noktalarına bakmak faydalıdır. Bir geliştiricinin yeni bir tür için if-else veya switch eklediği her nokta, soyutlama için adaydır. OCP'ye göre tasarlanmış bir sistemin öngörülebilir genişletme noktaları vardır: "yeni bir tür eklemek için bu arayüzü uygulayın" diyen belgelere sahip arayüzler. Android'de, ViewModelProvider.Factory ile Factory kalıbı açık bir örnektir — yeni bir ViewModel türü eklemek mevcut fabrikaları değiştirmeyi gerektirmez.
En etkili kalıplar mobil geliştirmede OCP'ye uymak için Strategy, Template Method, Decorator ve Factory'dir. Her biri, farklı nesne yönelimli tasarım mekanizmaları aracılığıyla mevcut kodu değiştirmeden davranışı genişletme sorununu çözer.
Strategy, ortak bir arayüz aracılığıyla algoritmaların anında değiştirilmesine olanak tanır. iOS geliştirmede, stratejiler animasyonlar ve form doğrulama için kullanılır. Template Method, bir algoritmanın iskeletini temel sınıfta tanımlar ve alt sınıflar adımları geçersiz kılar — ortak yapıya ancak farklı içeriğe sahip ekranlar için uygundur.
Decorator, bir nesnenin sınıfını değiştirmeden dinamik olarak davranış ekler. Android'de Decorator, bir Repository'nin önbellek veya günlük katmanıyla sarılması için kullanılır. Factory Method, bir arayüz aracılığıyla nesneler oluşturur ve alt sınıfların hangi sınıfı örnekleyeceğine karar vermesine olanak tanır — OCP uyumlu bağımlılık oluşturmanın temeli.
Kalıp seçimi, genişletilen davranışın istikrarına bağlıdır. Strategy, algoritmalar tamamen değiştirildiğinde idealdir. Template Method — yapı sabit ancak adımlar değişken olduğunda. Decorator — genişletme istemci için şeffaf olması gerektiğinde. Android ve iOS'taki çoğu senaryo için Strategy + bağımlılık enjeksiyonu yeterlidir.
Bu kalıpları OCP olmadan uygulamak teknik olarak mümkündür ancak anlamını kaybeder. Neden ek bir soyutlama seviyesi eklediğimizi haklı çıkaran OCP'dir: sistemin mevcut kodu yeniden yazmadan büyüyebilmesi için.
Ödeme işleme ile bir Android örneğini ele alalım. OCP olmadan, her yeni ödeme sistemi için işleyici sınıfında değişiklik gerekir. OCP ile, mevcut kod değiştirilmeden yeni bir arayüz uygulaması eklenir.
// OCP ihlali: yeni sistem eklendiğinde switch değişiklik gerektirir
class BadPaymentProcessor {
fun process(type: String) {
when (type) {
"card" -> // kart işleme
"paypal" -> // PayPal işleme
}
}
}
// OCP uyumlu tasarım
interface PaymentMethod {
fun pay(amount: Double)
}
class CardPayment : PaymentMethod {
override fun pay(amount: Double) { }
}
class PayPalPayment : PaymentMethod {
override fun pay(amount: Double) { }
}
// Yeni sistem — yeni sınıf, mevcut kod değiştirilmeden
class ApplePayPayment : PaymentMethod {
override fun pay(amount: Double) { }
}
Metin alanı doğrulama ile bir iOS örneği, Swift protokolleri aracılığıyla aynı mantığı gösterir:
// OCP uyumlu doğrulama
protocol ValidationRule {
func validate(_ input: String) -> Bool
}
struct EmailRule: ValidationRule {
func validate(_ input: String) -> Bool {
return input.contains("@")
}
}
struct PhoneRule: ValidationRule {
func validate(_ input: String) -> Bool {
return input.count == 11
}
}
// Yeni bir kural eklemek doğrulayıcı kodunun değiştirilmesini gerektirmez
struct PasswordRule: ValidationRule {
func validate(_ input: String) -> Bool {
return input.count >= 8
}
}
Bu örneklerde OCP'nin temel avantajı: ApplePay veya PasswordRule eklemek mevcut sınıfları değiştirmeyi gerektirmez. Kod yatay olarak genişler — eski dosyaları değiştirerek değil, yeni dosyalar aracılığıyla. Bu, gerileme riskini azaltır ve yeni işlevselliğin uygulanmasını hızlandırır.
En yaygın ihlal, nesne türüne dayalı bir switch veya when yapısıdır. Her yeni tür eklendiğinde, kodaki tüm bu switch'leri bulmak ve yeni bir dal eklemek gerekir. Atlanan bir switch, derleme zamanında tespit edilmesi zor bir çalışma zamanı hatasıdır.
Mobil geliştirmede, enum değerine bağlı yöntemlere sahip devasa enum sınıfları kullanıldığında OCP ihlal edilir. Yeni bir enum öğesi eklemek, proje genelindeki her switch'in değiştirilmesini gerektirir. Alternatif, her türün kendi davranışını uyguladığı bir arayüz aracılığıyla çok biçimliliktir.
Bir diğer tipik ihlal, God Adapter'dır: if-else aracılığıyla farklı hücre türlerini işleyen RecyclerView.Adapter (Android) veya UITableViewDataSource (iOS). Her yeni hücre türü, bağdaştırıcının genişletilmesini gerektirir. Çözüm, ortak bir bind yöntemine sahip çok biçimli bir ViewHolder'dır, burada her hücre türü kendi görüntülemesinden sorumludur.
Önleyici tedbirler şunları içerir: çok biçimlilik lehine tür tabanlı switch'ten kaçınmak, arayüzler aracılığıyla bağımlılıkları enjekte etmek ve yapılandırmaya göre nesneler oluşturmak için Factory kalıbını kullanmak. "Türe göre anahtar" için kodu analiz etmek, OCP odaklı ekiplerde kod incelemesinin zorunlu bir parçasıdır.
Mevcut bir OCP ihlalini yeniden düzenleme, Replace Conditional with Polymorphism aracılığıyla yapılır: her koşullu dal, ortak bir arayüz uygulayan ayrı bir sınıf haline gelir. İstemci kodu, arayüzle çalışacak şekilde yeniden yazılır ve somut uygulama bir fabrika veya DI kabı aracılığıyla sağlanır.
OCP ve çok biçimliliğin tüm genişletme sorunlarını çözmediğini anlamak önemlidir. Mimari yanlış seçilirse, yeni işlevsellik eklemek yalnızca uygulamaları değil, aynı zamanda sözleşmeleri de değiştirmeyi gerektirecektir. İyi mimari, genişletme yönlerini tahmin eder ve soyutlamaları tam bu noktalara yerleştirir. OCP'ye yapılan yatırımlar, proje ne kadar uzun yaşar ve belirli modüllerin gereksinimleri ne kadar sık değişirse o kadar karşılığını verir.
Sıkça Sorulan Sorular
Hayır. OCP, aynı soyutlamayla ilgili yeni işlevsellik eklerken mevcut kodu değiştirmeyi yasaklar. Bir sözleşmeyi değiştirmek, hataları düzeltmek ve yeniden düzenleme yapmak OCP ihlali değildir — prensip, genişletme sırasında basamaklı değişikliklere karşı korur.
Strategy, OCP'nin doğrudan bir uygulamasıdır. Strateji arayüzü sözleşmeyi tanımlar, istemci soyutlamaya bağlıdır ve somut stratejiler değişken davranışı uygular. Yeni bir strateji eklemek istemciyi değiştirmeyi gerektirmez — bu, değişikliğe kapalılıkla birlikte genişlemeye açıklıktır.
Evet, kalıtım ve Template Method aracılığıyla: temel sınıf algoritmanın iskeletini tanımlar ve alt sınıflar adımları geçersiz kılar. Ancak kalıtım güçlü bir bağlılık oluşturur ve arayüzlerden daha az esnektir. Modern geliştirmede, arayüzler ve kompozisyon OCP'yi uygulamanın tercih edilen yolu olarak kabul edilir.
OCP uyumlu kod test etmeyi basitleştirir: her arayüz uygulaması izole olarak test edilir. İstemci kodu, belirli bir davranışa bağlanmadan mantığın doğrulanmasına olanak tanıyan bir mock uygulamasıyla test edilir. Sistemi genişletmek mevcut testleri yeniden yazmayı gerektirmez.
Hayır. OCP, işlevsel genişletme öngörülebilir olduğunda haklıdır. Genişletilmesi planlanmayan istikrarlı kod için ek soyutlama aşırıdır. YAGNI (You Ain't Gonna Need It), OCP için iyi bir dengeleyicidir: soyutlama, ikinci bir davranış varyantı ortaya çıktığında tanıtılır, önceden değil.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun