C# Üst Düzey Tasarım Kalıpları
Tasarım kalıpları, nesne yönelimli kodu daha verimli ve sürdürülebilir bir şekilde yapısal ve uygulamak için şablonlar sağlayarak, yaygın yazılım geliştirme sorunlarına çözümler sunar. Nesnelerin oluşturulması, yapısı ve iletişimi konularında geliştiricilere esnek ve ölçeklenebilir bir şekilde sorunları çözmeleri için yardımcı olurlar. Tasarım kalıpları, geliştiricilere daha iyi kod yazmalarında rehberlik eden en iyi uygulama kavramları olarak hizmet eder. Yazılım tasarımında temel ilkelerden biri, SOLID ilkelerinin bir parçası olan Tek Sorumluluk İlkesi (SRP)'dir.
Tim Corey "Tasarım Kalıpları: C#'ta Pratikte Tek Sorumluluk İlkesi Açıklandı (SOLID İçindeki S)" videosunda Tek Sorumluluk İlkesi (SRP)'ni inceleyerek yazılım tasarımındaki önemini vurgular ve etkili bir şekilde nasıl uygulanacağına dair pratik bilgiler sunar. Bu makale, videosunun önemli noktalarına ilişkin kısa bir genel bakış sunarak, temiz ve sürdürülebilir kod oluşturmanın önemini vurgular.
SRP'ye Giriş
Yazılım tasarımında, SOLID ilkeleri, sürdürülebilir ve ölçeklenebilir kod oluşturmak için çok önemlidir. Kodun anlaşılır, test edilebilir ve değiştirilebilir olmasını sağlarlar. Beş ilke—Tek Sorumluluk İlkesi (SRP), Açık/Kapalı İlkesi (OCP), Liskov Yerine Geçme İlkesi (LSP), Arayüz Ayırma İlkesi (ISP), ve Bağımlılık Ters Çevirme İlkesi (DIP)—nesne yönelimli tasarım için temeldir ve çözümün daha sağlam hale getirilmesi için tasarım kalıplarına uygulanabilir.
C#'ta tasarım kalıplarını uygulayarak, geliştiriciler yaygın sorunları daha etkili bir şekilde çözebilir. Nesneler oluşturmak, ağaç yapıları tanımlamak veya tek örneklerle yeniden kullanılabilirliği sağlamak için tasarım kalıpları, yazılım mimarisini geliştiren önceden tanımlanmış çözümler sunar. Fabrika Yöntemi, Builder ve Singleton gibi kalıplar esnek, yeniden kullanılabilir çözümler sağlarken, davranışsal ve yapısal kalıplar karmaşıklığı yönetmeye ve sistem içinde iletişimi geliştirmeye yardımcı olur. Bu kalıpları öğrenerek ve kullanarak, geliştiriciler daha kolay sürdürülebilir ve genişletilebilir sistemler inşa edebilir.
Tim, geliştiriciler için en iyi uygulamaları izlemelerini sağlamak adına SRP konseptini vurguluyor. SRP, bir sınıfın yalnızca bir sorumluluğu veya değişme nedeni olması gerektiğini belirtir. Bu ilke, temiz, sürdürülebilir ve ölçeklenebilir kodun korunmasına yardımcı olur.
Demo Kodu Genel Bakışı
Tim, kullanıcının ilk ve soyadını soran, bu isimleri doğrulayan ve ardından bir kullanıcı adı oluşturan basit bir C# konsol uygulaması ayarlar. İlk uygulama, SRP'yi ihlal eder, kodun bu ilkeye uyması için nasıl yeniden düzenleneceğini göstermek için mükemmel bir fırsat sunar.
SRP Açıklandı
Tim, başlangıç sınıfındaki birden fazla sorumluluğu vurgulayarak SRP'yi açıklar:
- Kullanıcı Etkileşimi: Hoşgeldin mesajlarını ve istemleri ele alma.
- Veri Yakalama: Kullanıcının ilk ve soyadını yakalama.
- Doğrulama: Girdi isimlerini doğrulama.
- Kullanıcı Adı Oluşturma: Giriş isimlerinden bir kullanıcı adı oluşturma.
Bu sorumlulukların her biri sınıfın değişmesi için farklı bir neden temsil eder, SRP'yi ihlal eder.
SRP'ye Uygun Hale Getirmek İçin Yeniden Düzenleme
Tim, her bir sorumluluğu kendi sınıfına ayırarak kodu SRP'ye uyması için nasıl yeniden düzenleyeceğini gösterir. Bu yaklaşım, her sınıfın değişmesi için tek bir nedeni olmasını sağlar, böylece kod daha modüler ve daha kolay sürdürülebilir hale gelir.
Pratik Örnek
Tim, bir yeniden düzenleme pratik örneği sunar:
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to my application");
Console.Write("Enter your first name: ");
string firstName = Console.ReadLine();
Console.Write("Enter your last name: ");
string lastName = Console.ReadLine();
if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName))
{
Console.WriteLine("You did not give us valid information!");
Console.ReadLine();
return;
}
var userName = $"{firstName.Substring(0, 1)}{lastName}".ToLower();
Console.WriteLine($"Your username is {userName}");
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
}using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to my application");
Console.Write("Enter your first name: ");
string firstName = Console.ReadLine();
Console.Write("Enter your last name: ");
string lastName = Console.ReadLine();
if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName))
{
Console.WriteLine("You did not give us valid information!");
Console.ReadLine();
return;
}
var userName = $"{firstName.Substring(0, 1)}{lastName}".ToLower();
Console.WriteLine($"Your username is {userName}");
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
}Adım Adım Yeniden Düzenleme
Adım 1: StandardMessages Sınıfını Oluşturma
Öncelikle, kullanıcıya gösterilen standart mesajları ele almak için bir sınıf oluşturur. Bu sınıf, karşılama mesajlarını ve bitiş mesajlarını yönetecek.
public class StandardMessages
{
public static void WelcomeMessage()
{
Console.WriteLine("Welcome to my application");
}
public static void EndApplication()
{
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
public static void ShowValidationErrorMessage()
{
Console.WriteLine("You did not give us valid information!");
}
}public class StandardMessages
{
public static void WelcomeMessage()
{
Console.WriteLine("Welcome to my application");
}
public static void EndApplication()
{
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
public static void ShowValidationErrorMessage()
{
Console.WriteLine("You did not give us valid information!");
}
}Program sınıfında, Console.WriteLine ve Console.ReadLine doğrudan çağrılarını StandardMessages sınıfındaki yöntemlere yapılan çağrılarla değiştirin:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
// Other code...
StandardMessages.EndApplication();
}
}class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
// Other code...
StandardMessages.EndApplication();
}
}Adım 2: PersonDataCapture Sınıfını Oluşturma
Sonra, kişinin ilk ve soyadını yakalamak için bir sınıf oluşturur. Bu sınıf, kullanıcı girdilerini toplama ve bir Person nesnesi döndürme sorumluluğuna sahip olacak.
public class PersonDataCapture
{
public static Person Capture()
{
Person output = new Person();
Console.Write("Enter your first name: ");
output.FirstName = Console.ReadLine();
Console.Write("Enter your last name: ");
output.LastName = Console.ReadLine();
return output;
}
}public class PersonDataCapture
{
public static Person Capture()
{
Person output = new Person();
Console.Write("Enter your first name: ");
output.FirstName = Console.ReadLine();
Console.Write("Enter your last name: ");
output.LastName = Console.ReadLine();
return output;
}
}Adım 3: Person Sınıfını Oluşturma
Ayrıca, kullanıcının ilk ve soyadını tutmak için bir Person sınıfına ihtiyaçınız olacak.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}Program sınıfında, doğrudan kullanıcı girişi işlemesini PersonDataCapture.Capture çağrısı ile değiştirin:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
// Other code...
StandardMessages.EndApplication();
}
}class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
// Other code...
StandardMessages.EndApplication();
}
}Adım 4: PersonValidator Sınıfını Oluşturma
Daha sonra, kişinin ilk ve soyadının doğrulanmasını ele almak için bir sınıf oluşturur. Bu sınıf isimlerin boş veya beyaz boşluk olmadığından emin olmaktan sorumlu olacak.
public class PersonValidator
{
public static bool Validate(Person person)
{
if (string.IsNullOrWhiteSpace(person.FirstName))
{
StandardMessages.ShowValidationErrorMessage("first name");
return false;
}
if (string.IsNullOrWhiteSpace(person.LastName))
{
StandardMessages.ShowValidationErrorMessage("last name");
return false;
}
return true;
}
}public class PersonValidator
{
public static bool Validate(Person person)
{
if (string.IsNullOrWhiteSpace(person.FirstName))
{
StandardMessages.ShowValidationErrorMessage("first name");
return false;
}
if (string.IsNullOrWhiteSpace(person.LastName))
{
StandardMessages.ShowValidationErrorMessage("last name");
return false;
}
return true;
}
}Program sınıfında, doğrulama kodunu PersonValidator.Validate çağrısı ile değiştirin:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
if (!PersonValidator.Validate(user))
{
StandardMessages.EndApplication();
return;
}
// Other code...
StandardMessages.EndApplication();
}
}class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
if (!PersonValidator.Validate(user))
{
StandardMessages.EndApplication();
return;
}
// Other code...
StandardMessages.EndApplication();
}
}Adım 7: AccountGenerator Sınıfını Oluşturma
Tim, kullanıcı adı oluşturma ve hesap yaratma mantığını yeni bir AccountGenerator sınıfına taşır.
AccountGenerator Sınıfını Oluşturma:
- Sınıf, kullanıcı adını oluşturma mantığını ve hesap oluşturmayı simüle etmeyi içerir.
public class AccountGenerator { public static void CreateAccount(Person user) { string username = $"{user.FirstName.Substring(0, 1)}{user.LastName}".ToLower(); Console.WriteLine($"Your username is: {username}"); } }public class AccountGenerator { public static void CreateAccount(Person user) { string username = $"{user.FirstName.Substring(0, 1)}{user.LastName}".ToLower(); Console.WriteLine($"Your username is: {username}"); } }Ana Sınıfı Güncelleme:
- Ana sınıfta hesabı oluşturmak için AccountGenerator'ı çağırın.
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
bool isUserValid = PersonValidator.Validate(user);
if (!isUserValid)
{
StandardMessages.EndApplication();
return;
}
AccountGenerator.CreateAccount(user);
StandardMessages.EndApplication();
}
}class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
bool isUserValid = PersonValidator.Validate(user);
if (!isUserValid)
{
StandardMessages.EndApplication();
return;
}
AccountGenerator.CreateAccount(user);
StandardMessages.EndApplication();
}
}
Özet ve Sonuçlar
Bu sonuç bölümünde, Tim Corey, demo kodun yeniden düzenleme süreci boyunca Tek Sorumluluk İlkesi (SRP) uygulanmasının faydalarını ve uygulamasını özetler. Başvurunun daha küçük, odaklanmış sınıflara ayrılmasının avantajlarını vurgular.
SRP'nin Temel Faydaları
Basitleştirilmiş Kod Bakımı:
Her sınıf, değişikliklerin nerede yapılması gerektiğini belirlemeyi kolaylaştıran tek bir sorumluluğa sahiptir. Örneğin, kullanıcı veri yakalama mantığı net bir şekilde PersonDataCapture altında yer alır.
- Bu yapı, kullanıcı doğrulamasını değiştirmek isteyen birinin PersonValidator'a bakması gerektiğini açık hale getirir.
Gelişmiş Okunabilirlik:
- Açıkça tanımlanmış sorumluluklarla ana program akışı daha okunabilir hale gelir. Kod şimdi bir dizi net, ardışık eylem gibi okunuyor:
StandardMessages.WelcomeMessage(); Person user = PersonDataCapture.Capture(); bool isUserValid = PersonValidator.Validate(user); if (!isUserValid) { StandardMessages.EndApplication(); return; } AccountGenerator.CreateAccount(user); StandardMessages.EndApplication();StandardMessages.WelcomeMessage(); Person user = PersonDataCapture.Capture(); bool isUserValid = PersonValidator.Validate(user); if (!isUserValid) { StandardMessages.EndApplication(); return; } AccountGenerator.CreateAccount(user); StandardMessages.EndApplication();Azaltılmış Karmaşıklık:
Odaklanmış sorumluluklara sahip küçük sınıflar, anlaşılması ve bakımı daha kolay olan daha az satır kod içerme eğilimindedir.
- Örnek: StandardMessages sınıfı yöntemleri özlüdür ve hoş geldiniz mesajını görüntülemek veya uygulamayı sonlandırmak gibi tek işlevler yapar.
public class StandardMessages { public static void WelcomeMessage() { Console.WriteLine("Welcome to my application"); } public static void EndApplication() { Console.WriteLine("Press enter to close..."); Console.ReadLine(); } public static void ShowValidationErrorMessage(string fieldName) { Console.WriteLine($"You did not give us a valid {fieldName}!"); } }public class StandardMessages { public static void WelcomeMessage() { Console.WriteLine("Welcome to my application"); } public static void EndApplication() { Console.WriteLine("Press enter to close..."); Console.ReadLine(); } public static void ShowValidationErrorMessage(string fieldName) { Console.WriteLine($"You did not give us a valid {fieldName}!"); } }
Kolay Kod Değişiklikleri:
Her sınıfın değişmesi için tek bir nedeni olduğundan, kodu yeni gereksinimlere yanıt olarak değiştirmek kolay olur.
- Örnek: Eğer gereksinim bitiş mesajını değiştirmekse, değişiklik yalnızca StandardMessages.EndApplication yönteminde gerçekleşir.
Daha İyi Hata Ayıklama ve İş Birliği:
Daha küçük, iyi tanımlanmış sınıflarla, bir sorun yerini kolayca tespit edebileceğiniz için hata ayıklama daha basit hale gelir.
- Yeni geliştiriciler, her sınıfın net yapısını ve sorumluluklarını anlayarak daha hızlı bir şekilde eğitilebilirler.
Birçok Sınıf Üzerine Endişelerin Giderilmesi
Tim, SRP uygulamanın, projeyi hantal hale getirerek çok fazla sınıfa neden olduğuna dair yaygın bir endişeyi ele alır:
Gezinme ve Anlama:
Visual Studio'daki IntelliSense gibi araçlar, birden fazla sınıfta gezinmeyi kolaylaştırır. Örneğin, F12'ye basmak yöntemlerin veya sınıfların tanımlarına doğrudan götürür.
- Çok sayıda küçük, yönetilebilir parçaya sahip olmak, büyük monolitik sınıflara kıyasla tüm uygulamayı anlamayı kolaylaştırabilir.
Performans ve Depolama:
- Eklenen sınıflar, modern depolama ve hesaplama yetenekleri göz önüne alındığında, disk alanı veya performansı önemli ölçüde etkilemez.
Denge ve Fazlalık:
Tim, denge bulmayı tavsiye eder. Bir sınıfın sorumluluğu çok büyümesine neden oluyorsa, değişim için birden fazla nedeni olup olmadığını düşünün, bu bölünmeye ihtiyaç duyabileceğini gösterir.
- Visual Studio'da bir sınıfta geniş kapsamda gezmeniz gerekiyorsa, bunun çok büyük olabileceğini ve bölünmesi gerektiğini öneriyor.
Pratik Uygulama
Tim, geliştiricileri özellikle mevcut kod tabanlarında SRP'yi kademeli olarak uygulamaya teşvik eder. SRP ilkelerine uyum sağlamak için küçük değişikliklerle ve yeni kodlarla başlayın. Bu kademeli yaklaşım, daha pürüzsüz geçişler ve sürekli iyileştirme sağlar.
Sonuç
Tim Corey'nin yeniden düzenleme örneği, Tek Sorumluluk İlkesi'ne (SRP) bağlı kalmanın daha temiz ve bakımı kolay kodla sonuçlandığını gösterir. Sorumlulukları daha küçük, odaklanmış sınıflara ayırarak geliştiriciler, kod tabanları içinde okunabilirliği, hata ayıklamayı ve iş birliğini iyileştirebilirler. SOLID tasarım desenlerinin bu temel ilkesi, yazılım geliştirmede daha ileri düzey prensiplere ve en iyi uygulamalara açılan kapıdır.
Daha ayrıntılı bilgi ve kod örnekleri için lütfen videosunu izleyin ve daha fazla tasarım deseni videosu için kanalını ziyaret edin.

