Open-Closed Principle, Strategy Design Pattern ve Yazılımın Sürdürülebilirliği
Giriş
Merhaba sevgili okuyucular!
Yazılım geliştirme süreçlerinde, projeler büyüdükçe yönetilmesi zorlaşabilir. Ancak bazı prensipler ve tasarım kalıpları ile bu karmaşayı asgariye indirebiliriz. Bugünkü makalemizde, SOLID prensiplerinin ikincisi olan Açıklık/Kapalılık Prensibi (Open/Closed Principle) ve bu prensibi pratikte nasıl uygulayabileceğimizi gösteren Strateji Tasarım Kalıbı’ndan (Strategy Design Pattern) bahsedeceğiz.
SOLID Prensipleri Olmadan Yazılımın Karşılaştığı Sorunlara Bakalım
Eğer Open-Closed ilkesi ve Strateji Tasarım Kalıbı’nı kullanmazsak ve tüm özellikleri tek bir sınıfta toplarsak, bu durumda yazılımımız nasıl görünürdü?
public class ShoppingCart {
private String paymentType;
public void setPaymentType(String paymentType) {
this.paymentType = paymentType;
}
public void checkout(int amount) {
if ("CreditCard".equals(paymentType)) {
System.out.println(amount + " tutarında kredi kartı ile ödeme yapıldı.");
} else if ("Paypal".equals(paymentType)) {
System.out.println(amount + " tutarında PayPal ile ödeme yapıldı.");
}
// Yeni ödeme yöntemleri için sürekli if-else blokları eklenecek.
}
}
Bu yapıdaki sorunlar:
- Yeni özellikler eklerken sürekli olarak mevcut kodu değiştirmek zorundayız.
- Kod tekrarı riski yüksek.
- Ödeme yöntemleri arasında yüksek bağımlılık var.
- Test etmesi zor.
Peki Open/Closed Prensibi Nedir?
Açık/Kapalı Prensibi, yazılım varlıklarının (sınıflar, modüller, fonksiyonlar vs.) yeni davranışlara açık, ancak mevcut özelliklerine kapalı olması gerektiğini belirtir. Ancak, bu prensip gerçekte nasıl işler?
Önce Strateji Tasarım Kalıbı ve Open/Closed Prensibi’nin Mükemmel Uyumuna Bakalım
Strategy (Strateji) tasarım kalıbı, davranışsal (behavioral) bir design pattern (tasarım kalıbı) olarak bilinir. Bu kalıbın ana fikri, bir algoritmayı veya işlevi sabit bir şekilde bir sınıfta tanımlamak yerine, bu işlevi veya algoritmayı değiştirilebilir ve genişletilebilir kılmaktır.
Temel Fikir: Bir işlevi veya algoritmayı, bir sınıfta sabit bir şekilde kodlamak yerine, bu işlevi veya algoritmayı bir dizi sınıfın her birinde tanımlarız. Bu sayede, bu işlevi veya algoritmayı, uygulama çalışırken dinamik olarak değiştirebiliriz.
Strategy Design Pattern’in (Strateji Tasarım Kalıbının) Bileşenleri:
- Strategy (Strateji Arayüzü): Tüm stratejilerin uygulayacağı bir interface (arayüz) veya abstract class (soyut sınıf)dır.
- ConcreteStrategy (Somut Stratejiler): Strategy interface’ini (arayüzünü) veya abstract class’ını (soyut sınıfını) implement eden (uygulayan) sınıflardır. Bu sınıflar, interface’de (arayüzde) tanımlanan işlevi veya algoritmayı gerçekleştirir.
- Context (Bağlam): Strategy (Strateji) nesnesini kullanarak bazı işlemleri gerçekleştiren sınıfdır. Context (Bağlam), hangi stratejinin kullanılacağına karar verir veya bu kararı dışarıdan alır.
Bu bileşenler sayesinde, yeni bir ödeme yöntemi eklemek istediğimizde, mevcut kodu değiştirmemize gerek kalmadan sadece yeni bir sınıf ekleyerek bu işlemi gerçekleştirebiliriz. Bu durum, Open/Closed prensibinin mükemmel bir örneğidir.
Simdi SOLID Prensiplerinden OpenClosed İlkesinin Strategy Design Pattern ile Sağladığı Çözüme Bakalım
// Strategy Arayüzünü oluşturalım
public interface PaymentStrategy {
void pay(int amount);
}
// ConcreteStrategy 1
public class CreditCardPayment implements PaymentStrategy {
// Kredi kartı ödeme yöntemi detayları
@Override
public void pay(int amount) {
System.out.println(amount + " tutarında kredi kartı ile ödeme yapıldı.");
}
}
// ConcreteStrategy 2
public class PaypalPayment implements PaymentStrategy {
// PayPal ödeme yöntemi detayları
@Override
public void pay(int amount) {
System.out.println(amount + " tutarında PayPal ile ödeme yapıldı.");
}
}
// Context
public class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
// Ana program
public class Main {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(500); // "500 tutarında kredi kartı ile ödeme yapıldı." çıktısını verir.
cart.setPaymentStrategy(new PaypalPayment());
cart.checkout(600); // "600 tutarında PayPal ile ödeme yapıldı." çıktısını verir.
}
}
Bu yapıda, yeni bir ödeme yöntemi eklemek istediğimizde, mevcut kodu değiştirmemize gerek kalmadan sadece yeni bir sınıf ekleyerek bu işlemi gerçekleştirebiliriz.
Sonuç:
Yazılım dünyasında esneklik ve genişletilebilirlik esastır. Strateji Tasarım Kalıbı ve Açıklık/Kapalılık Prensibi, bu ihtiyaçlara mükemmel bir çözüm sunar. Bu yaklaşımlarla, yazılımlarımızın sürdürülebilirliği artar, bakımı kolaylaşır ve yeni özelliklerin eklenmesi sırasında mevcut özelliklerin bozulma riski azalır. Yazılımın temel prensiplerine sadık kalarak ve doğru tasarım kalıplarını kullanarak daha sağlam, esnek ve sürdürülebilir yazılımlar geliştirebiliriz.
İlerleyen yazılarımızda sizlerle beraber öğrenmeye devam edeceğiz. Takipte kalın! 👋