Earn More by Sharing What You Love
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!

Tim Corey
35m 50s
Wzorce projektowe są wielokrotnie używanymi rozwiązaniami typowych problemów z zakresu tworzenia oprogramowania, dostarczającymi szablony do strukturyzacji i implementacji kodu obiektowego w bardziej efektywny i łatwiejszy do utrzymania sposób. Pomagają programistom rozwiązywać problemy z tworzeniem obiektów, strukturą i komunikacją w elastyczny i skalowalny sposób. Wzorce projektowe służą jako najlepsze praktyki, które pomagają deweloperom w pisaniu lepszego kodu. Jedną z podstawowych zasad projektowania oprogramowania jest Zasada Pojedynczej Odpowiedzialności (SRP), która jest częścią zasad SOLID.
W swoim wideo, "Design Patterns: Single Responsibility Principle Explained Practically in C# (The S in SOLID)", Tim Corey bada Zasadę Pojedynczej Odpowiedzialności (SRP), podkreślając jej znaczenie w projektowaniu oprogramowania i dostarczając praktyczne wskazówki, jak skutecznie ją wdrażać. Ten artykuł oferuje zwięzły przegląd kluczowych wniosków z jego wideo, podkreślając znaczenie SRP w tworzeniu czystego, łatwego do utrzymania kodu.
W projektowaniu oprogramowania zasady SOLID są kluczowe dla tworzenia łatwego do utrzymania i skalowania kodu. Zapewniają, że kod jest łatwy do zrozumienia, testowania i modyfikacji. Pięć zasad—Zasada Pojedynczej Odpowiedzialności (SRP), Zasada Otwartych/Zamkniętych (OCP), Zasada Podstawienia Liskov (LSP), Zasada Segregacji Interfejsów (ISP) i Zasada Odwrócenia Zależności (DIP)—są integralną częścią projektowania obiektowego i można je zastosować we wzorcach projektowych, aby uczynić rozwiązania bardziej solidnymi.
Stosując wzorce projektowe w C#, programiści mogą skuteczniej rozwiązywać typowe problemy. Niezależnie czy chodzi o tworzenie obiektów, definiowanie struktur drzewiastych, czy zapewnianie reużywalności dla pojedynczych instancji, wzorce projektowe dostarczają wstępnie zdefiniowanych rozwiązań, które zwiększają architekturę oprogramowania. Wzorce takie jak Metoda Fabryki, Konstruktor i Singleton dostarczają elastycznych, wielokrotnego użytku rozwiązań, podczas gdy wzorce behawioralne i strukturalne pomagają zarządzać złożonością i poprawiać komunikację w systemach. Ucząc się i wykorzystując te wzorce, programiści mogą budować systemy, które są łatwiejsze do utrzymania i rozwijania.
Tim omawia koncepcję SRP, podkreślając, że dla programistów kluczowe jest, aby ich kod spełniał najlepsze praktyki. SRP mówi, że klasa powinna mieć tylko jedną odpowiedzialność lub powód do zmiany. Ta zasada pomaga utrzymać czysty, łatwy do utrzymania i skalowalny kod.
Tim konfiguruje prostą aplikację konsolową w C#, która prosi użytkownika o imię i nazwisko, sprawdza te nazwy i generuje nazwę użytkownika. Początkowa implementacja narusza SRP, co stanowi doskonałą okazję do pokazania, jak można zrefaktorować kod, aby spełniał tę zasadę.
Tim wyjaśnia SRP, podkreślając różne odpowiedzialności w początkowej klasie:
Każda z tych odpowiedzialności stanowi inny powód do zmiany klasy, co narusza SRP.
Tim pokazuje, jak zrefaktorować kod, aby przestrzegał SRP, wyodrębniając każdą odpowiedzialność do osobnej klasy. To podejście zapewnia, że każda klasa ma jeden powód do zmiany, co sprawia, że kod jest bardziej modułowy i łatwiejszy do utrzymania.
Tim dostarcza praktyczny przykład refaktoryzacji:
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();
}
}Imports System
Module Program
Sub Main(args As String())
Console.WriteLine("Welcome to my application")
Console.Write("Enter your first name: ")
Dim firstName As String = Console.ReadLine()
Console.Write("Enter your last name: ")
Dim lastName As String = Console.ReadLine()
If String.IsNullOrWhiteSpace(firstName) OrElse String.IsNullOrWhiteSpace(lastName) Then
Console.WriteLine("You did not give us valid information!")
Console.ReadLine()
Return
End If
Dim userName = $"{firstName.Substring(0, 1)}{lastName}".ToLower()
Console.WriteLine($"Your username is {userName}")
Console.WriteLine("Press enter to close...")
Console.ReadLine()
End Sub
End ModuleNajpierw Tim tworzy klasę do obsługi standardowych komunikatów wyświetlanych użytkownikowi. Ta klasa będzie zarządzać komunikatami powitalnymi i końcowymi.
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 Shared Sub WelcomeMessage()
Console.WriteLine("Welcome to my application")
End Sub
Public Shared Sub EndApplication()
Console.WriteLine("Press enter to close...")
Console.ReadLine()
End Sub
Public Shared Sub ShowValidationErrorMessage()
Console.WriteLine("You did not give us valid information!")
End Sub
End ClassW klasie Program zastąp bezpośrednie wywołania Console.WriteLine i Console.ReadLine wywołaniami metod w klasie StandardMessages:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
// Other code...
StandardMessages.EndApplication();
}
}Module Program
Sub Main(args As String())
StandardMessages.WelcomeMessage()
' Other code...
StandardMessages.EndApplication()
End Sub
End ModuleNastępnie Tim tworzy klasę do obsługi przechwytywania imienia i nazwiska osoby. Ta klasa będzie odpowiedzialna za zbieranie danych od użytkownika i zwracanie obiektu Person.
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 Shared Function Capture() As Person
Dim output As New Person()
Console.Write("Enter your first name: ")
output.FirstName = Console.ReadLine()
Console.Write("Enter your last name: ")
output.LastName = Console.ReadLine()
Return output
End Function
End ClassPotrzebujesz również klasy Person do przechowywania imienia i nazwiska użytkownika.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}Public Class Person
Public Property FirstName As String
Public Property LastName As String
End ClassW klasie Program zastąp bezpośrednie przetwarzanie danych użytkownika wywołaniem PersonDataCapture.Capture:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
// Other code...
StandardMessages.EndApplication();
}
}Module Program
Sub Main(args As String())
StandardMessages.WelcomeMessage()
Dim user As Person = PersonDataCapture.Capture()
' Other code...
StandardMessages.EndApplication()
End Sub
End ModuleNastępnie Tim tworzy klasę do obsługi weryfikacji imienia i nazwiska osoby. Ta klasa będzie odpowiedzialna za upewnienie się, że nazwy nie są null lub puste.
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 Shared Function Validate(person As Person) As Boolean
If String.IsNullOrWhiteSpace(person.FirstName) Then
StandardMessages.ShowValidationErrorMessage("first name")
Return False
End If
If String.IsNullOrWhiteSpace(person.LastName) Then
StandardMessages.ShowValidationErrorMessage("last name")
Return False
End If
Return True
End Function
End ClassW klasie Program zastąp kod weryfikacji wywołaniem PersonValidator.Validate:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
if (!PersonValidator.Validate(user))
{
StandardMessages.EndApplication();
return;
}
// Other code...
StandardMessages.EndApplication();
}
}Module Program
Sub Main(args As String())
StandardMessages.WelcomeMessage()
Dim user As Person = PersonDataCapture.Capture()
If Not PersonValidator.Validate(user) Then
StandardMessages.EndApplication()
Return
End If
' Other code...
StandardMessages.EndApplication()
End Sub
End ModuleTim przenosi logikę generowania nazwy użytkownika i tworzenia konta do nowej klasy AccountGenerator.
Tworzenie klasy AccountGenerator:
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 Shared Sub CreateAccount(user As Person)
Dim username As String = $"{user.FirstName.Substring(0, 1)}{user.LastName}".ToLower()
Console.WriteLine($"Your username is: {username}")
End Sub
End ClassAktualizacja klasy głównej:
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();
}
}Module Program
Sub Main(args As String())
StandardMessages.WelcomeMessage()
Dim user As Person = PersonDataCapture.Capture()
Dim isUserValid As Boolean = PersonValidator.Validate(user)
If Not isUserValid Then
StandardMessages.EndApplication()
Return
End If
AccountGenerator.CreateAccount(user)
StandardMessages.EndApplication()
End Sub
End Module
W tej kończącej sekcji Tim Corey podsumowuje korzyści i wdrażanie Zasady Pojedynczej Odpowiedzialności (SRP) poprzez proces refaktoryzacji kodu demo. Podkreśla zalety podziału aplikacji na mniejsze, skoncentrowane klasy.
Uproszczona konserwacja kodu:
Każda klasa ma jedną odpowiedzialność, co ułatwia lokalizację miejsc do wprowadzenia zmian. Na przykład, logika przechwytywania danych użytkownika jest jednoznacznie umieszczona w PersonDataCapture.
Ta struktura ułatwia zrozumienie, ponieważ każdy, kto chce zmodyfikować weryfikację użytkownika, zna, aby sprawdzić PersonValidator.
Poprawiona czytelność:
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
bool isUserValid = PersonValidator.Validate(user);
if (!isUserValid)
{
StandardMessages.EndApplication();
return;
}
AccountGenerator.CreateAccount(user);
StandardMessages.EndApplication();StandardMessages.WelcomeMessage()
Dim user As Person = PersonDataCapture.Capture()
Dim isUserValid As Boolean = PersonValidator.Validate(user)
If Not isUserValid Then
StandardMessages.EndApplication()
Return
End If
AccountGenerator.CreateAccount(user)
StandardMessages.EndApplication()Zmniejszona złożoność:
Małe klasy z ukierunkowanymi odpowiedzialnościami mają tendencję do mniejszej liczby linii kodu, co sprawia, że są łatwiejsze do zrozumienia i utrzymania.
Przykład: Metody klasy StandardMessages są zwięzłe i mają jednoznaczne cele, takie jak wyświetlanie komunikatu powitalnego lub kończenie aplikacji.
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 Shared Sub WelcomeMessage()
Console.WriteLine("Welcome to my application")
End Sub
Public Shared Sub EndApplication()
Console.WriteLine("Press enter to close...")
Console.ReadLine()
End Sub
Public Shared Sub ShowValidationErrorMessage(fieldName As String)
Console.WriteLine($"You did not give us a valid {fieldName}!")
End Sub
End Class
Łatwość wprowadzania zmian w kodzie:
Ponieważ każda klasa ma jeden powód do zmiany, modyfikowanie kodu w odpowiedzi na nowe wymagania staje się prostsze.
Przykład: Jeśli wymaganiem jest zmiana komunikatu końcowego, zmiana zachodzi wyłącznie w metodzie StandardMessages.EndApplication.
Lepsze debugowanie i współpraca:
Z mniejszymi, dobrze zdefiniowanymi klasami, debugowanie staje się prostsze, ponieważ łatwo określić lokalizację problemu.
Nowi deweloperzy mogą szybciej się wdrożyć, rozumiejąc jasną strukturę i odpowiedzialności każdej klasy.
Tim porusza często występującą obawę, że zastosowanie SRP skutkuje zbyt wieloma klasami, co czyni projekt nieporęcznym:
Nawigacja i zrozumienie:
Narzędzia takie jak IntelliSense w Visual Studio ułatwiają nawigację po wielu klasach. Na przykład, naciskając F12, przechodzi się bezpośrednio do definicji metod lub klas.
Posiadanie wielu małych, zarządzalnych części może ułatwić zrozumienie całej aplikacji w porównaniu do dużych klas monolitycznych.
Wydajność i przechowywanie:
Równowaga i nadmiar:
Tim radzi, aby znaleźć równowagę. Jeśli odpowiedzialność klasy powoduje, że staje się ona zbyt duża, zastanów się, czy ma wiele powodów do zmiany, co może wskazywać na potrzebę dalszego podziału.
Sugeruje, że jeśli trzeba przescrollować obszernie przez klasę w Visual Studio, może być zbyt duża i wymagać podziału.
Tim zachęca programistów do wprowadzania SRP stopniowo, zwłaszcza w istniejących bazach kodu. Zacznij od małych zmian i nowego kodu, aby dostosować się do zasad SRP. Takie stopniowe podejście zapewnia sprawniejsze przejścia i ciągłe doskonalenie.
Przykład refaktoryzacji Tim Coreya pokazuje, jak przestrzeganie Zasady Pojedynczej Odpowiedzialności (SRP) prowadzi do czystszego, łatwiejszego do utrzymania kodu. Dzieląc odpowiedzialności na mniejsze, skoncentrowane klasy, programiści mogą poprawić czytelność, debugowanie i współpracę w swoich bazach kodu. Ta podstawowa zasada wzorców projektowych SOLID otwiera drogę do bardziej zaawansowanych zasad i najlepszych praktyk w tworzeniu oprogramowania.
Aby uzyskać bardziej szczegółowe informacje i przykłady kodu, obejrzyj jego wideo i odwiedź jego kanał po więcej filmów o wzorcach projektowych.
Do you create content for developers working with .NET, C#, Java, Python, or Node.js? Turn your expertise into extra income!
Join our newsletter, you’ll get exclusive access on article updates. We value your privacy