C# En İyi Tasarım Desenleri
[[academy-video-youtube({"vid": "5RwhyZnVRS8", "start_time": "0", "title": "C# En İyi Tasarım Desenleri", "creator": "Tim Corey", "length": "35m 50s"})]]
Tasarım desenleri, yaygın yazılım geliştirme problemlerine yeniden kullanılabilir çözümler sağlayarak, nesne yönelimli kodu daha verimli ve sürdürülebilir bir şekilde yapılandırmak ve uygulamak için şablonlar sunar. Geliştiricilerin esnek ve ölçeklenebilir bir şekilde nesne yaratımı, yapı ve iletişim problemlerini çözmesine yardımcı olurlar. Tasarım desenleri, geliştiricilere daha iyi kod yazma konusunda yol gösteren 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'dir (SRP).
Videoda, "Tasarım Desenleri: Tek Sorumluluk İlkesi C#'ta Pratik Olarak Açıklanmıştır (SOLID'deki S)", Tim Corey, Tek Sorumluluk İlkesi'ni (SRP) inceliyor ve yazılım tasarımındaki önemini vurgulayarak, onu etkili bir şekilde uygulamak için pratik bilgiler sağlıyor. Bu makale, videosundan ana çıkarımların özlü bir genel bakışını sunarak, temiz, sürdürülebilir kod yaratmada SRP'nin önemini vurguluyor.
SRP'ye Giriş
Yazılım tasarımında, SOLID prensipleri sürdürülebilir ve ölçeklenebilir kod oluşturmak için önemlidir. Kodun anlaşılmasını, test edilmesini ve değiştirilmesini kolaylaştırırlar. Beş prensip – Tek Sorumluluk İlkesi (SRP), Açık/Kapalı İlkesi (OCP), Liskov'un Yerine Geçme İlkesi (LSP), Arayüz Ayrımı İlkesi (ISP) ve Bağımlılık Ters Çevirmesi İlkesi (DIP) – nesne yönelimli tasarımın ayrılmaz parçasıdır ve çözümleri daha sağlam hale getirmek için tasarım desenleri içinde uygulanabilir.
C#'ta tasarım desenlerini uygulayarak, geliştiriciler daha yaygın problemleri daha etkili bir şekilde çözebilirler. Nesne yaratımı, ağaç yapıları tanımlama veya tekil örneklerle tekrar kullanılabilirliği sağlama gibi durumlar söz konusu olduğunda, tasarım desenleri, yazılım mimarisini geliştiren önceden tanımlanmış çözümler sunar. Fabrika Metodu, Builder ve Singleton gibi desenler esnek, yeniden kullanılabilir çözümler sağlarken, davranışsal ve yapısal desenler karmaşıklığı yönetir ve sistemlerde iletişimi geliştirir. Bu desenleri öğrenip kullanarak, geliştiriciler bakımı ve genişletilmesi kolay sistemler oluşturabilirler.
Tim, SRP kavramını tartışırken geliştiricilerin kodlarının en iyi uygulamalara uyum sağladığından emin olmalarının ne kadar önemli olduğunu vurgular. SRP, bir sınıfın yalnızca bir sorumluluğu veya değişim nedeni olması gerektiğini belirtir. Bu ilke, temiz, sürdürülebilir ve ölçeklenebilir kodun korunmasına yardımcı olur.
Demo Koduna Genel Bakış
Tim, C#'ta kullanıcıdan ad ve soyadını isteyen, bu adları doğrulayan ve ardından bir kullanıcı adı oluşturan basit bir konsol uygulaması kurar. İlk uygulama SRP'yi ihlal eder, bu da ilkenin nasıl uygulanacağını göstermek için mükemmel bir fırsat yaratır.
SRP Açıklaması
Tim, başlangıçtaki sınıfın içindeki birden fazla sorumluluğu vurgulayarak SRP'yi açıklar:
- Kullanıcı Etkileşimi: Karşılama mesajları ve istemleri ile ilgilenme.
- Veri Yakalama: Kullanıcının adını ve soyadını yakalama.
- Doğrulama: Girdi adlarının doğrulanması.
- Kullanıcı Adı Oluşturma: Girdi adlarından bir kullanıcı adı oluşturma.
Bu sorumlulukların her biri, SRP'yi ihlal ederek sınıfın değişmesi için farklı bir nedeni temsil eder.
SRP'ye Uyum Sağlamak için Yeniden Düzenleme
Tim, her sorumluluğu kendi sınıfına ayırarak kodun SRP'ye uyması için nasıl yeniden düzenleneceğini gösterir. Bu yaklaşım, her sınıfın değişmek için tek bir nedeni olmasını sağlayarak, kodu daha modüler ve bakımı daha kolay hale getirir.
Pratik Örnek
Tim, yeniden düzenlemenin pratik bir örneğini 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 Tim, kullanıcıya gösterilen standart mesajlar ile ilgili bir sınıf oluşturur. Bu sınıf, karşılama mesajlarını ve son mesajları yönetecektir.
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'a yapılan doğrudan çağrıları StandardMessages sınıfındaki metodlara 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, Tim kişilerin ad ve soyadını yakalamak için bir sınıf oluşturur. Bu sınıf, kullanıcı girdilerini toplamak ve bir Person nesnesi döndürmekten sorumlu olacaktır.
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 adını ve soyadını tutmak için bir Person sınıfına ihtiyacınız var.
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ı girdisi kontrolünü PersonDataCapture.Capture çağrısıyla 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
Sonra, Tim kişilerin ad ve soyadlarının geçerliliğini kontrol etmek için bir sınıf oluşturur. Bu sınıf, adların null olmamasını veya boşluk olmamasını sağlamaktan sorumlu olacaktır.
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, geçerlilik kodunu PersonValidator.Validate çağrısıyla 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 oluşturma 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 ve hesap oluşturmayı simüle etme mantığını 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 çağrı yapı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 bitirici bölümde, Tim Corey, demo kodunun yeniden düzenlenmesi süreci boyunca Tek Sorumluluk Prensibi (SRP) uygulamasının faydalarını ve uygulamasını özetler. Uygulamayı daha küçük, odaklanmış sınıflara ayırmanın avantajlarını vurgular.
SRP'nin Ana Faydaları
Basitleştirilmiş Kod Bakımı:
Her sınıfın tek bir sorumluluğu vardır, bu da değişikliklerin nerede yapılması gerektiğini bulmayı kolaylaştırır. Örneğin, kullanıcı verisi yakalama mantığı açıkça PersonDataCapture altında yer alır.
- Bu yapı, kullanıcı doğrulamasını değiştirmek isteyen birisinin nerede kontrol edeceğini bilmesi nedeniyle anlayışı basitleştirir.
Geliştirilmiş Okunabilirlik:
- Açıkça tanımlanmış sorumluluklarla, ana program akışı daha okunabilir hale gelir. Kod şimdi bir dizi net, ardışık eylem gibi okunur:
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, daha az kod satırına sahiptir, bu da onları anlamayı ve bakımı kolaylaştırır.
- Örneğin: StandardMessages sınıfı yöntemleri kısa ve tek amaca hizmet eder, örneğin karşılama mesajı göstermeye veya uygulamayı sonlandırmaya.
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}!");
}
}Kod Değişikliklerinin Kolaylığı:
Her sınıfın değişmek için tek nedeni olduğundan, yeni gereksinimlere yanıt olarak kodu değiştirmek kolaylaşır.
- Örnek: Gereksinim son mesajı değiştirmek olduğunda, değişiklik sadece StandardMessages.EndApplication yönteminde gerçekleşir.
Daha İyi Hata Ayıklama ve İşbirliği:
Küçük, iyi tanımlanmış sınıflarla, hata ayıklama daha basit hale gelir çünkü sorunun yerini kolayca bulabilirsiniz.
- Yeni geliştiriciler, her sınıfın net yapısını ve sorumluluklarını anlayarak daha hızlı işbaşı yapabilir.
Birçok Sınıf Üzerine Endişelerin Giderilmesi
Tim, SRP'yi uygulamanın çok fazla sınıfa yol açarak projeyi hantal hale getirdiği yönündeki yaygın bir endişeyi ele alır:
Gezinti ve Anlayış:
Visual Studio'daki IntelliSense gibi araçlar, birden fazla sınıf arasında gezinmeyi kolaylaştırır. Örneğin, F12 tuşuna bastığınızda yöntemlerin veya sınıfların tanımına doğrudan geçiş yaparsınız.
- Ç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:
- Ek sınıflar, modern depolama ve bilgisayar yetenekleri dikkate alındığında, disk alanı veya performansı üzerinde önemli bir etki yaratmaz.
Denge ve Aşırılık:
Tim, bir denge bulmanızı önerir. Bir sınıfın sorumluluğu, çok büyümesine neden oluyorsa, birden fazla değişim nedenine sahip olup olmadığını değerlendirin, bu, daha fazla bölünmesi gerektiğini gösterebilir.
- Geniş bir şekilde kaydırmak zorunda kalıyorsanız, Visual Studio'da bir sınıf üzerinde kaydırma yapmanız gerekiyorsa, bu sınıfın çok büyük olduğunu ve bölünmesi gerektiğini gösterir.
Pratik Uygulama
Tim geliştiricilere özellikle mevcut kod tabanlarında SRP'yi kademeli olarak uygulamalarını önerir. Küçük değişikliklerle başlayın ve yeni kodu SRP ilkelerine uygun olarak hizalayın. Bu kademeli yaklaşım, geçişlerin daha düzenli olmasını ve sürekli iyileştirilmesini sağlar.
Sonuç
Tim Corey'nin yeniden düzenleme örneği, Tek Sorumluluk Prensibi'ne (SRP) uymanın daha temiz, daha bakımlı kodlarla sonuçlandığını gösterir. Sorumlulukları daha küçük, odaklanmış sınıflara ayırarak geliştiriciler, kod tabanlarında okunabilirliği, hata ayıklamayı ve işbirliğini geliştirebilir. Yazılım geliştirmede daha gelişmiş ilkeler ve en iyi uygulamalar için yol açan SOLID tasarım kalıplarının bu temel ilkesi.
Daha detaylı bilgi ve kod örnekleri için lütfen onun videosunu izleyin ve daha fazla tasarım kalıbı videoları için kanalını ziyaret edin.

