Single Responsibility Principle (SRP)

Single Responsibility Principle (SRP)

“THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO  CHANGE”

Tasarlanan her sınıfın sadece tek bir sorumluluğu olmalı ve sınıfın değişikliğe uğraması için birden fazla neden olmamalıdır. SRP,  birbirine sıkı sıkıya bağlı olan sınıflarla benzerlik göstermektedir. Prensibe tasarımsal olarak baktığımızda ise sınıf bir sorumluğu yerine getirirken diğer sınıf fonksiyoneliteyi gerçekleştirmektedir. Buradaki sorumluğu netleştirecek olursak, sınıfın sadece tekbir metod içereceği anlamına gelmez. Sorumluluk sınıf içerisinde bir çok metod kullanılarak gerçekleştirilebilir.


SRP neden gereklidir?

Bir çok sorumluluğu ve bir çok fonksiyonelitesi olan sınıflar tasarlayabiliriz, bu durum bizim sorumluluğumuza kalmıştır. Ancak tasarladığınız bu sınıfın bağlılıklarını düşündüğüzde geliştirme zamanı içerisinde yapılacak bir fonksiyonel bir değişikliğin, gerçekleştirilen diğer fonksiyonellikleri ne ölçüde etkileyeceğini öngöremeyiz. Böyle bir durumda birbirine bağlı olan tüm fonksiyonellikleri test etmemiz gerekir. Otomatik testlerimiz olduğunu varsaysak bile yapmanız gereken tüm değişiklikleri göz önüne aldığımızda geliştirme zamanımızın ne kadar uzayacağını göz önünde bulundumamız gerekir. Her şeyi göze alıp bu şekilde geliştirmeye devam etsek bile tasarladığımız sınıfta bulunan kodlar esnek olmayacak (Rigidity) ve kırılganlık (Fragility) durumu ortaya çıkacaktır.

Bu durumu önlemek için, sınıf fonksiyonelliklerini SRP’de belirtildiği gibi sorumluluklarına göre bölmemiz gerekir.

Prensibi açıklayacak örnek verecek olursak;

Bir kullanıcının sisteme giriş yapıp profili ile ilgili bilgileri değiştirebileceği ve kimlik bilgileri kontrol edecek bir sınıf tasarladığımızı düşünelim.


internal class UserSettingsService
{
  public void SetBackgroundColor(ConsoleColor color)
  {
    CheckAccess();
    Console.BackgroundColor = color;
    Console.WriteLine("Arka plan rengi değişti.");
  }

  private static void CheckAccess()
  {
     if (IsCurrentUserLogedIn())
     {
       throw new SecurityException("Arka plan rengi değiştirilemedi. Geçersiz kullanıcı bilgileri.");
     }
  }

  private static bool IsCurrentUserLogedIn()
  {
     return Thread.CurrentPrincipal.Identity.IsAuthenticated;
  }
}

Şu an için herşey normal görünüyor. Ancak CheckAccess kodunu başka bir sınıfta tekrar kullanmak istediğinizde yada CheckAccess kodu çalıştıktan sonra başka işlemler yapmak istediğinizde yada kullanıcı bilgilerini her değiştirdiğinde email onayı gerektiği gibi durumlarda, sınıf tasarımını her defasında değiştirmenız gerekir ki bu da anlamsızdır.

Peki bu durumu düzeltmek için SRP tanımında bahsettiğimiz gibi UserSettingService sınıfını tek bir sorumluluk alacak sekilde ayrıştıralım. UserSettingService sınıfını UserSettingService sınıfı ve SecurityService sınıfı olarak tekrar tasarlıyalım ve CheckAccess metodunu SecurityService sınıfına taşıyalım.

internal class UserSettingsService
{
  public void SetBackgroundColor(ConsoleColor color)
  {
     SecurityService.CheckAccess();
     Console.BackgroundColor = color;
     Console.WriteLine("- Color is changed...");
  }
}

internal class SecurityService
{
  public static void CheckAccess()
  {
     if (IsCurrentUserLogedIn())
     {
       throw new SecurityException("Arka plan rengi değiştirilemedi. Geçersiz kullanıcı bilgileri.");
     }
  }
  private static bool IsCurrentUserLogedIn()
  {
     return Thread.CurrentPrincipal.Identity.IsAuthenticated;
  }
}

Sonuç olarak her sınıf kendi sorumluluğunu yerine getirebilecek hale geldi ve SRP prensibine uygun bir tasarım gerçekleştirmiş olduk.

Kaynak;

Resim, © Jennifer M. Kohnke

Agile Principles, Patterns, and Practices in C# 

Bir cevap yazın