• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

YASA - Yet another S.O.L.I.D. article

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Understanding SOLID Principles in .NET: Write Better, Scalable, and Maintainable Code


The SOLID principles are the cornerstone of good software design. Whether you're building small applications or large enterprise systems in .NET, applying these principles can help you write code that is easier to understand, maintain, and extend.

In this article, we'll explore each of the SOLID principles with practical C# examples in the .NET ecosystem.

? What is SOLID?


SOLID is an acronym for five object-oriented design principles:

  • S – Single Responsibility Principle
  • O – Open/Closed Principle
  • L – Liskov Substitution Principle
  • I – Interface Segregation Principle
  • D – Dependency Inversion Principle

These principles were introduced by Robert C. Martin and have become a standard for writing clean and maintainable software.

1. Single Responsibility Principle (SRP)

"A class should have only one reason to change."
This means that a class should only have one job or responsibility.

❌ Bad Example


public class Invoice
{
public void CalculateTotal() { /* ... */ }
public void SaveToDatabase() { /* ... */ }
public void PrintInvoice() { /* ... */ }
}

Here, Invoice is doing too much — it calculates, persists data, and handles printing.

✅ Good Example


public class InvoiceCalculator
{
public void CalculateTotal() { /* ... */ }
}

public class InvoiceRepository
{
public void SaveToDatabase() { /* ... */ }
}

public class InvoicePrinter
{
public void PrintInvoice() { /* ... */ }
}

Each class now has a single responsibility.

2. Open/Closed Principle (OCP)

"Software entities should be open for extension, but closed for modification."
This principle promotes the use of abstractions so that the behavior of a module can be extended without modifying its source code.

❌ Bad Example


public class Discount
{
public double CalculateDiscount(string customerType)
{
if (customerType == "Regular") return 0.1;
if (customerType == "Premium") return 0.2;
return 0;
}
}
✅ Good Example


public interface IDiscountStrategy
{
double GetDiscount();
}

public class RegularCustomerDiscount : IDiscountStrategy
{
public double GetDiscount() => 0.1;
}

public class PremiumCustomerDiscount : IDiscountStrategy
{
public double GetDiscount() => 0.2;
}

Now you can add new strategies without modifying existing code.

3. Liskov Substitution Principle (LSP)

"Derived classes must be substitutable for their base classes."
This principle asserts that objects of a superclass should be replaceable with objects of its subclasses without altering the correctness of the program. In simpler terms, subclasses should enhance, not weaken or break, the behavior promised by the base class.

Violating LSP often introduces unexpected behavior, especially in polymorphic code, and can lead to fragile systems.

❌ Bad Example


public class Bird
{
public virtual void Fly() { /* default flying logic */ }
}

public class Ostrich : Bird
{
public override void Fly()
{
throw new NotImplementedException();
}
}

In this example, Ostrich inherits from Bird and overrides the Fly method by throwing an exception. This violates LSP because any code that expects a Bird to fly safely might crash or behave incorrectly when passed an Ostrich.

✅ Better Design


public interface IBird { }

public interface IFlyingBird : IBird
{
void Fly();
}

public class Sparrow : IFlyingBird
{
public void Fly() { /* flying logic */ }
}

public class Ostrich : IBird
{
// No Fly method; ostriches do not fly
}

This approach respects LSP by not requiring Ostrich to implement functionality it does not possess. Clients depending on IFlyingBird know all implementations can fly, while those dealing with general IBird don't make assumptions about flying.

? Key Takeaways

  • Avoid forcing subclasses to override or disable base class functionality.
  • Design with appropriate abstractions that reflect real capabilities.
  • Ensure derived classes honor the expectations set by the base class.

By following LSP, you ensure that components remain interchangeable, reducing bugs and making your code more robust and extensible.

4. Interface Segregation Principle (ISP)

"Clients should not be forced to depend on interfaces they do not use."
❌ Bad Example


public interface IWorker
{
void Work();
void Eat();
}

public class Robot : IWorker
{
public void Work() { /* ... */ }
public void Eat() => throw new NotImplementedException();
}
✅ Good Example


public interface IWorkable
{
void Work();
}

public interface IEatable
{
void Eat();
}

public class Human : IWorkable, IEatable
{
public void Work() { /* ... */ }
public void Eat() { /* ... */ }
}

public class Robot : IWorkable
{
public void Work() { /* ... */ }
}

Separate interfaces make code more flexible.

5. Dependency Inversion Principle (DIP)

"Depend on abstractions, not on concretions."
High-level modules should not depend on low-level modules. Both should depend on abstractions.

❌ Bad Example


public class EmailService
{
public void SendEmail(string message) { /* ... */ }
}

public class Notification
{
private EmailService _emailService = new EmailService();
public void Send(string message)
{
_emailService.SendEmail(message);
}
}
✅ Good Example


public interface IMessageService
{
void Send(string message);
}

public class EmailService : IMessageService
{
public void Send(string message) { /* ... */ }
}

public class Notification
{
private readonly IMessageService _messageService;

public Notification(IMessageService messageService)
{
_messageService = messageService;
}

public void Notify(string message)
{
_messageService.Send(message);
}
}

Now Notification is not tightly coupled to EmailService.

✅ Final Thoughts


Applying the SOLID principles in .NET helps you build:

  • Modular and testable components
  • Easier-to-understand codebases
  • Scalable applications ready for change

While not every class needs to follow all principles strictly, being mindful of SOLID will gradually elevate the quality of your code.

If you found this article helpful follow me on

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

,

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

and

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

for more content.

Thanks for reading!


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу