Single Responsibility Principle

Kağan Saygın
9 min readJun 2, 2021

--

SOLID prensiplerinin S si olan SRP, kısaca tek sorumluluk tek iş prensibini inceleyeceğiz.

Bir nesne, sadece bir iş yapıyor olmalı, bir nesne içinde birden fazla değişiklik yapmanız gerekiyorsa bu prensibe uymuyorsunuzdur. Çünkü bir sınıf ne kadar fazla sorumluluk alırsa, o kadar fazla değiştirmek zorunda kalırsınız.

Single Responsibility Prensibinin (SRP) bize sağladığı bazı avantajlar

  • Karmaşıklığı azaltır
  • Kod okunabilirliği kolaylaştırır
  • Yönetimi kolaylaştırır
  • Yeniden kullanılabilirlik sağlar

Zihnimizde canlandırmak için şöyle bir senaryo düşünün

Tatile büyük bir otele gidiyoruz ve otelin resepsiyonunda bizi RESEPSİYONİST karşılıyor.

  1. RESEPSİYONİST bizden kimlik istiyor ve işlemlerini yapıyor.(Kimliklerin ve bilgilerin sisteme işlenmesi, kolluk kuvvetlerine bildirmesi)
  2. RESEPSİYONİST oda kartını BELLBOYA veriyor.
  3. BELLBOY bizim valizlerimizi odamıza taşıyor. (Bahşişimizi veriyoruz :) )
  4. Çıkış işlemi için tekrar resepsiyona gidiyoruz RESEPSİYONİST çıkış işlemlerini yapıyor.
  5. KAT HİZMETLERİ, çıkış yaptıktan sonra odamızı temizliyor.

Arkadaşlar senaryoda da olduğu gibi Bellboy, Resepsiyon, Kat Hizmetleri her departmanın farklı görevleri ve sorumlulukları var.

Projemizi yazarken de aslında böyle düşünmeliyiz yani projemizi aslında departmanlara ayırmalıyız.

Bir proje ile örneklendirelim, projemizde senaryodaki otel örneğinden gidelim ve otel sistemine müşterileri web API üzerinden kaydedelim. Kötü bir kod ile başlayalım.

Web API Projemizi oluşturuyoruz.

  1. Models klasörü oluşturuyoruz.
  2. Models klasörünün içerisine Customer modelimizi oluşturuyoruz.
public class Customer
{
public int Id { get; set; }
public string IdentificationNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}

3.Müşteri ekleyebilmek için CustomerController oluşturuyoruz.

Bizden istenen şimdilik müşterileri kaydetmek fakat şöyle bir problemimiz var. Müşteri eklerken TC kimlik numarasını doğrulamamız ve önceden kayıtlı değilse sisteme kaydetmemiz gerekiyor. İlk olarak TC kimlik numarası kontrolü ile başlayalım.

TC kimlik numarası kontrolü için Murat Öner’in yazdığı buradaki kodu kullanacağız.

bool returnvalue = false;
if (tcKimlikNo.Length == 11)
{
Int64 ATCNO, BTCNO, TcNo;
long C1,C2,C3, C4, C5,C6,C7,C8, C9,Q1,Q2;

TcNo = Int64.Parse(tcKimlikNo);

ATCNO = TcNo / 100;
BTCNO = TcNo / 100;

C1 = ATCNO % 10; ATCNO = ATCNO / 10 ;
C2 = ATCNO % 10; ATCNO = ATCNO / 10 ;
C3 = ATCNO % 10; ATCNO = ATCNO / 10 ;
C4 = ATCNO % 10; ATCNO = ATCNO / 10 ;
C5 = ATCNO % 10; ATCNO = ATCNO / 10 ;
C6 = ATCNO % 10; ATCNO = ATCNO / 10 ;
C7 = ATCNO % 10; ATCNO = ATCNO / 10 ;
C8 = ATCNO % 10; ATCNO = ATCNO / 10 ;
C9 = ATCNO % 10; ATCNO = ATCNO / 10 ;
Q1 = ((10-((((C1+C3+C5+C7+C9)*3)+(C2+C4+C6+C8))%10))%10);
Q2 = ((10-(((((C2+C4+C6+C8)+Q1)*3)+(C1+C3+C5+C7+C9))%10))%10);

returnvalue = ((BTCNO * 100)+(Q1 * 10)+Q2 == TcNo);
}
return returnvalue;

CustomerController kodlarını aşağıda ki gibi düzenliyoruz.

[HttpPost]
public IActionResult Add(Customer customer)
{
//Tc No Kontrol
bool returnvalue = false;
if (customer.IdentificationNumber.Length == 11)
{
Int64 ATCNO, BTCNO, TcNo;
long C1, C2, C3, C4, C5, C6, C7, C8, C9, Q1, Q2;
TcNo = Int64.Parse(customer.IdentificationNumber);ATCNO = TcNo / 100;
BTCNO = TcNo / 100;
C1 = ATCNO % 10; ATCNO = ATCNO / 10;
C2 = ATCNO % 10; ATCNO = ATCNO / 10;
C3 = ATCNO % 10; ATCNO = ATCNO / 10;
C4 = ATCNO % 10; ATCNO = ATCNO / 10;
C5 = ATCNO % 10; ATCNO = ATCNO / 10;
C6 = ATCNO % 10; ATCNO = ATCNO / 10;
C7 = ATCNO % 10; ATCNO = ATCNO / 10;
C8 = ATCNO % 10; ATCNO = ATCNO / 10;
C9 = ATCNO % 10; ATCNO = ATCNO / 10;
Q1 = ((10 - ((((C1 + C3 + C5 + C7 + C9) * 3) + (C2 + C4 + C6 + C8)) % 10)) % 10);
Q2 = ((10 - (((((C2 + C4 + C6 + C8) + Q1) * 3) + (C1 + C3 + C5 + C7 + C9)) % 10)) % 10);
returnvalue = ((BTCNO * 100) + (Q1 * 10) + Q2 == TcNo);
}
if (!returnvalue) return BadRequest("Tc Kimlik No Geçersiz!");return Ok("Kayıt Başarılı");
}

Projemizi çalıştırıp bir Postman uygulaması ile test edelim.

  1. Yeni Sekme Açıyoruz ve URL giriyoruz.
  2. Get Methodunu Post olarak değiştiriyoruz çünkü controllerı o şekilde ayarladık.
  3. Body > Raw > Json seçiyoruz. Çünkü Customer(müşteri) bilgilerini post etmemiz gerekiyor.
  4. Customer bilgilerimizi JSON formatında yazıyoruz ve Send ile gönderiyoruz.
{
"IdentificationNumber":"0123456789",
"FirstName":"KAĞAN",
"LastName":"SAYGIN"
}

Gördüğünüz gibi TC kimlik numarasını yanlış girdik ve cevap olarak;

5. Http durum kodu olarak “404 Bad Request” yani geçersiz istek cevabı aldık.

6. “TC Kimlik No Geçersiz!” mesajını cevap olarak aldık.

Gerçek TC kimlik numaramı girdiğimde;

Http durum kodu: “200 OK” ve mesajda “Kayıt Başarılı” şeklinde cevap aldık.

Şimdi projemizdeki 2. Adıma geçebiliriz. Müşteri önceden kayıtlı ise tekrar kayıt yapılmasın.

Bunun için öncelikle CustomerController içine sahte birkaç tane müşteri oluşturacağız ve TC kimlik kontrolünden sonra müşterinin önceden kayıtlı olup olmadığını sorgulayacağız.

//Müşteriler
List<Customer> customerList = new List<Customer>
{
new Customer{Id=1,IdentificationNumber="0000000000", FirstName = "Ayşe",LastName = "Yılmaz"},
new Customer{Id=2,IdentificationNumber="1111111111", FirstName = "Fatma",LastName = "Kaya"},
new Customer{Id=3,IdentificationNumber="2222222222", FirstName = "Hayriye",LastName = "Demir"},
new Customer{Id=4,IdentificationNumber="test için tc no giriniz", FirstName = "KAĞAN",LastName = "SAYGIN"},
};
//Tc No Kontrol
bool returnvalue = false;
if (customer.IdentificationNumber.Length == 11)
{
Int64 ATCNO, BTCNO, TcNo;
long C1, C2, C3, C4, C5, C6, C7, C8, C9, Q1, Q2;
TcNo = Int64.Parse(customer.IdentificationNumber);ATCNO = TcNo / 100;
BTCNO = TcNo / 100;
C1 = ATCNO % 10; ATCNO = ATCNO / 10;
C2 = ATCNO % 10; ATCNO = ATCNO / 10;
C3 = ATCNO % 10; ATCNO = ATCNO / 10;
C4 = ATCNO % 10; ATCNO = ATCNO / 10;
C5 = ATCNO % 10; ATCNO = ATCNO / 10;
C6 = ATCNO % 10; ATCNO = ATCNO / 10;
C7 = ATCNO % 10; ATCNO = ATCNO / 10;
C8 = ATCNO % 10; ATCNO = ATCNO / 10;
C9 = ATCNO % 10; ATCNO = ATCNO / 10;
Q1 = ((10 - ((((C1 + C3 + C5 + C7 + C9) * 3) + (C2 + C4 + C6 + C8)) % 10)) % 10);
Q2 = ((10 - (((((C2 + C4 + C6 + C8) + Q1) * 3) + (C1 + C3 + C5 + C7 + C9)) % 10)) % 10);
returnvalue = ((BTCNO * 100) + (Q1 * 10) + Q2 == TcNo);
}
if (!returnvalue) return BadRequest("Tc Kimlik No Geçersiz!");//Müşterinin önceden kayıdı var mı?
var CheckIfCustomerExists = customerList.FirstOrDefault(c => c.IdentificationNumber == customer.IdentificationNumber);
//Eğer boş değilse
if (CheckIfCustomerExists != null) return BadRequest("Müşteri Önceden Kayıt Edilmiş!");
//Kayıt İşlemleri
return Ok("Kayıt Başarılı");

Postman ile tekrar son halini test edelim, kendi Tc numaramı gönderdiğimde Http 404 Bad Request ve mesajı cevap olarak aldık.

Projemiz bitti ve şuana kadar her şey güzel, projemiz başarılı bir şekilde çalışıyor. Aslında konumuz şimdi başlıyor.

Single Responsibility Principle (SRP)

Projede de gördüğünüz gibi bütün kodlarımızı Controller içine yazdık ve prensibimize uymadığımızı fark ettik. Nasıl mı?

  • Birden Fazla Sorumluk Aldı
  1. Müşterileri oluşturduk.
  2. TC kimlik kontrolü yaptık.
  3. Müşteri kayıt kontrolü yaptık.
  4. Kayıt ekleme işlemlerini de yaptığımızı farz edelim

Burada öngöremediğimiz bir kaç şey var aslında, şöyle düşünelim mesela TC kimlik numarasını bir kaç yerde daha kontrol etmeniz gerekecek. Örneğin müşteri güncellemesinde de yanlış TC kimlik numarası girilmesini istemeyiz o zaman buradaki kodları alıp güncelleme işlemi yaptığımız yere yapıştırdığınızı düşünelim. Sonra TC kimlik numarası kontrolü başka bir yerde daha lazım oldu, oraya da kodumuzu yapıştırdık diyelim. Sonra da bu kodda bir değişiklik yapmamız isteniyor. Kodları kopyaladığımız her birinde tek tek değiştirmemiz gerekecek veya TC kimlik numarasını nvi üzerinden kontrol etmemiz istendi gene tümünü tek tek değiştirmemiz gerekecek.

Artık sorunlarımızı anladığımız için şimdi hem Single Responsibility Principle uygulayalım hem de çözümlerimizi düşünelim ve oluşturalım.

  • TC kimlik numarasını kontrol eden sınıf oluşturalım,
  • Müşteri kontrolü için bir sınıf oluşturalım ve müşteri ile ilgili işlemleri burada yapalım,
  • ResultModel adında bir sınıf oluşturalım, müşteri ile ilgili işlemlerin sonucunda yanıt olarak bize mesaj ve doğru veya yanlış cevabı döndürsün.

İlk Olarak Model Klasörünün altında > ResultModel sınıfımı oluşturuyoruz.

public class ResultModel {    public bool Success { get; set; }    public string Message { get; set; } }

Business adında bir klasör oluşturuyoruz ve içine TC kimlik numarası kontrolü için TCNumberValidation sınıfımı oluşturuyoruz.

public static class TcNumberValidation
{
public static bool Validation(string tcKimlikNo)
{
bool returnvalue = false;
if (tcKimlikNo.Length == 11)
{
Int64 ATCNO, BTCNO, TcNo;
long C1, C2, C3, C4, C5, C6, C7, C8, C9, Q1, Q2;
TcNo = Int64.Parse(tcKimlikNo);ATCNO = TcNo / 100;
BTCNO = TcNo / 100;
C1 = ATCNO % 10; ATCNO = ATCNO / 10;
C2 = ATCNO % 10; ATCNO = ATCNO / 10;
C3 = ATCNO % 10; ATCNO = ATCNO / 10;
C4 = ATCNO % 10; ATCNO = ATCNO / 10;
C5 = ATCNO % 10; ATCNO = ATCNO / 10;
C6 = ATCNO % 10; ATCNO = ATCNO / 10;
C7 = ATCNO % 10; ATCNO = ATCNO / 10;
C8 = ATCNO % 10; ATCNO = ATCNO / 10;
C9 = ATCNO % 10; ATCNO = ATCNO / 10;
Q1 = ((10 - ((((C1 + C3 + C5 + C7 + C9) * 3) + (C2 + C4 + C6 + C8)) % 10)) % 10);
Q2 = ((10 - (((((C2 + C4 + C6 + C8) + Q1) * 3) + (C1 + C3 + C5 + C7 + C9)) % 10)) % 10);
returnvalue = ((BTCNO * 100) + (Q1 * 10) + Q2 == TcNo);
}
return returnvalue;
}
}

Business klasörünün içine müşteri işlemlerini yapacağımız CustomerManager sınıfını oluşturuyoruz.

içerisindeki metotlar

# public ResultModel Add(Customer customer)

// Müşteri eklemek için customer model ister, geriye ResultModel döndürür.

public ResultModel Add(Customer customer)
{
ResultModel resultModel = new ResultModel();
//Tc Kimlik Numarası Kontrol
if (!TcNumberValidation.Validation(customer.IdentificationNumber))
{
resultModel.Message = "Tc Kimlik No Geçersiz!";
resultModel.Success = false;
return resultModel;
}
//Müşterinin önceden kayıdı var mı?
if (!CheckIfCustomerExists(customer.IdentificationNumber))
{
resultModel.Message = "Müşteri Önceden Kayıt Edilmiş!";
resultModel.Success = false;
return resultModel;
}
//Veritabanı Kayıt İşlemleri.....
resultModel.Message = "Müşteri Kayıt Başarılı!";
resultModel.Success = true;
return resultModel;
}

# private bool CheckIfCustomerExists(string tcNumber)

//TC kimlik kontrolü için string tipinde TC kimlik numarası ister, geriye true veya false döndürür.

private bool CheckIfCustomerExists(string tcNumber)
{
bool result = false;
//Müşterinin önceden kayıdı var mı?
var findCustomer = fakeDB().FirstOrDefault(c => c.IdentificationNumber == tcNumber);
if (findCustomer == null) return true;return result;
}

#public List<Customer> fakeDB()

//Sahte veri tabanı olarak düşünebiliriz, sahte müşteriler oluşturur, müşteri listesi döndürür.

public List<Customer> fakeDB()
{
//Müşteriler
List<Customer> customerList = new List<Customer>
{
new Customer{Id=1,IdentificationNumber="0000000000", FirstName = "Ayşe",LastName = "Yılmaz"},
new Customer{Id=2,IdentificationNumber="1111111111", FirstName = "Fatma",LastName = "Kaya"},
new Customer{Id=3,IdentificationNumber="2222222222", FirstName = "Hayriye",LastName = "Demir"},
new Customer{Id=4,IdentificationNumber="", FirstName = "KAĞAN",LastName = "SAYGIN"},
};
return customerList;
}

CustomerManager.cs Tüm Kodlar

public class CustomerManager
{
public ResultModel Add(Customer customer)
{
ResultModel resultModel = new ResultModel();
//Tc Kimlik Numarası Kontrol
if (!TcNumberValidation.Validation(customer.IdentificationNumber))
{
resultModel.Message = "Tc Kimlik No Geçersiz!";
resultModel.Success = false;
return resultModel;
}
//Müşterinin önceden kayıdı var mı?
if (!CheckIfCustomerExists(customer.IdentificationNumber))
{
resultModel.Message = "Müşteri Önceden Kayıt Edilmiş!";
resultModel.Success = false;
return resultModel;
}
//Veritabanı Kayıt İşlemleri.....
resultModel.Message = "Müşteri Kayıt Başarılı!";
resultModel.Success = true;
return resultModel;
}
private bool CheckIfCustomerExists(string tcNumber)
{
bool result = false;
//Müşterinin önceden kayıdı var mı?
var findCustomer = fakeDB().FirstOrDefault(c => c.IdentificationNumber == tcNumber);
if (findCustomer == null) return true;return result;
}
public List<Customer> fakeDB()
{
//Müşteriler
List<Customer> customerList = new List<Customer>
{
new Customer{Id=1,IdentificationNumber="0000000000", FirstName = "Ayşe",LastName = "Yılmaz"},
new Customer{Id=2,IdentificationNumber="1111111111", FirstName = "Fatma",LastName = "Kaya"},
new Customer{Id=3,IdentificationNumber="2222222222", FirstName = "Hayriye",LastName = "Demir"},
new Customer{Id=4,IdentificationNumber="", FirstName = "KAĞAN",LastName = "SAYGIN"},
};
return customerList;
}
}

Projemizin sonuna geldik, yaptığımız değişiklikleri nasıl kullanacağız? CustomerController içindeki kodları şu şekilde düzenliyoruz:

[HttpPost]
public IActionResult Add(Customer customer)
{
CustomerManager customerManager = new CustomerManager();
//Post ile gelen müşteriyi ekle ve dönen cevabı resulta aktar
var result = customerManager.Add(customer);
//eğer false dönerse cevap olarak HttpKodu BadRequest, Mesaj olarakta customerManager dönen mesajı gönder
if (!result.Success) BadRequest(result.Message);
//True ise customerManager dönen mesajı gönder
return Ok(result.Message);
}

--

--

No responses yet