Open Closed Principle (OCP)

Open Closed Principle (OCP)

”Software entities (Classes, modules, functions) should be OPEN for EXTENSION, CLOSED for MODIFICATION.”

Geliştirilen sistemlerin yaşam süreleri boyunca değişimlere uğrayabileceği göz önüne alındığında, bu prensip genişletilmeye açık ama değişikliğe kapalı varlıkların (Sınıf, Method vs.) kullanılmasını önerir.

Peki yazılımın kaynak kodunu değiştirmeden, geliştirdiğimiz modullerin böyle bir davranış sergilemesini sağlayabiliriz?
Bu soruyu soyutlayarak (abstraction) diye cevaplayabiliriz. Bir sınıfı soyutlayarak manupule edebilirz.


Örneğin bir sınıf sabit soyut bir yapıya bağlı ise değişime kapalıdır. Yine aynı şekilde bir sınıf soyut bir yapıyı miras alarak genişletilebilmektedir.

Günümüzde kurumsal çözümlerin genelinde, müşteri ihtiyaçları doğrultusunda yazılımların devamlı güncellendiğini gözlemleyebilirz. Bu durumda yazılımın kodlarını değiştirmeden ilerlememiz pek mümkün olmamaktadır. Yapılacak değişiklikleri en aza indirgemek ve geliştirme zamanındaki riskleri azaltmak istediğimizde OCP kullanacağımız prensiplerden bir tanesidir.

Tüm bu bahsettiklerimi emailler için spam kontrolü yapan bir örnek üzerinde anlatacak olursak;

Sender, Receipent, Subject, ve Body den oluşan Mail sınıfımız aşağıdaki gibi olsun:

public class EMail
{
   public string Sender { get; set; }
   public string Recipient { get; set; }
   public string Subject { get; set; }
   public string Body { get; set; }

   public EMail(string sender, string recipient,string subject, string body)
   {
     Sender = sender;
     Recipient = recipient;
     Subject = subject;
     Body = body;
   }
}
public enum SpamResult
{
   Spam,Ok,Unknown
}

Şimdide mailin spam olup olmadığını kontrol edecek sınıfımızı oluşturulalım ve bu burada spam kontrol kurallarına bağlı olarak kontrolümüzü gerçekleştirelim :

public class RuleChecker
{
   public SpamResult CheckMail(EMail mail)
   {
     var result = TestRule1(mail);
     if(result != SpamResult.Unknown)
     return result;

     result = TestRule2(mail);

     if (result != SpamResult.Unknown)
     return result;
     // …
     return SpamResult.Unknown;
   }

   private SpamResult TestRule1(EMail mail)
   {
     // Spam kontrol kuralı 1
   }
   private SpamResult TestRule2(EMail mail)
   {
     // Spam kontrol kuralı 2
   }
}

Açıkça görüldüğü üzere böyle bir tasarım Open Closed prensibinin belirttiği gibi genişlemeye açık bir tasarım değildir ve devamlı değişime uyrayacak bir yapıdadır. Yeni bir spam kuralı tanımlandığında her defasında CheckMail() metodunun yeniden düzenlenmesi gerekmektedir. Önemli diğer bir nokta ise izole durumda olan CheckMail() metodu içerisinde yer alan somut kuralları test edemiyor olmamızdır.

Open Closed prensibine bağlı kalarak bu tasarımı elden geçirdiğimizde aşağıdaki gibi bir yapı oluşturmuş olacağız:

public interface ISpamRule
{
    SpamResult CheckMail(EMail mail);
}

public class RuleChecker
{
    private readonly IEnumerable<ISpamRule> _rules;
    public RuleChecker(IEnumerable<ISpamRule> rules)
    {
        _rules = rules;
    }

    public SpamResult CheckMail(EMail mail)
    {
        foreach (var rule in _rules)
        {
            var result = rule.CheckMail(mail);
            if (result != SpamResult.Unknown)
                return result;
        }
        return SpamResult.Unknown;
    }
}

Şimdi RuleChecker.CheckMail() metodundaki her yeni kural için kolaylıkla unit test oluşturabiliriz.

Artık spam kontrolü için oluşturacağınız RuleChecker sınıfı instance’ı için constructor’da hangi kurallara göre kontrol yapılacağını belirtip objemizi oluşturabiliriz.

class MyFirstRule : ISpamRule
{
    public SpamResult CheckMail(EMail mail)
    {
        // Spam kontrol kuralı 1
    }
}

class MySecondRule : ISpamRule
{
    public SpamResult CheckMail(EMail mail)
    {
        // Spam kontrol kuralı 2
    }
}
// …
var ruleChecker =
    new RuleChecker(
        new List<ISpamRule>
        {
            new MyFirstRule(),
            new MySecondRule(),
            // …
        });

Kaynaklar;

Resim, © Jennifer M. Kohnke
Agile Principles, Patterns, and Practices in C# 
Steffen Forkmann Blog

Bir cevap yazın