Опишите принципы SOLID, приведите пример каждого принципа на C# или Java и обсудите ситуации, когда строгое следование SOLID может привести к избыточности или противоречиям

25 Фев в 09:39
17 +1
0
Ответы
1
SOLID — набор из .........5 принципов объектно‑ориентированного проектирования, повышающих гибкость и сопровождаемость кода.
.........1. Single Responsibility Principle (SRP)
Каждый класс/модуль должен иметь только одну причину для изменения (одну ответственность).
Пример (C# — нарушение → исправление):
```csharp
// Нарушение: один класс генерирует и сохраняет отчёт
class Report {
public string Build() => "content";
public void Save(string path, string content) { /* запись в файл */ }
}
// Исправление: разделяем ответственности
class ReportBuilder {
public string Build() => "content";
}
class ReportSaver {
public void Save(string path, string content) { /* запись в файл */ }
}
```
Пояснение: разделение упрощает тестирование и изменение формата/места сохранения.
.........2. Open/Closed Principle (OCP)
Классы должны быть открыты для расширения, но закрыты для модификации.
Пример (C#):
```csharp
interface IShape { double Area(); }
class Rectangle : IShape { public double Width, Height; public double Area() => Width*Height; }
class Circle : IShape { public double Radius; public double Area() => Math.PI*Radius*Radius; }
class AreaCalculator {
public double TotalArea(IEnumerable shapes) => shapes.Sum(s => s.Area());
}
```
Пояснение: чтобы добавить новую фигуру, не меняем AreaCalculator — добавляем новый класс, реализующий IShape.
.........3. Liskov Substitution Principle (LSP)
Наследник должен быть взаимозаменяем с базовым типом без изменения корректности программы.
Пример (классическое нарушение — Rectangle / Square, C#):
```csharp
class Rectangle { public virtual int Width, Height; public int Area() => Width*Height; }
class Square : Rectangle {
public override int Width { set { base.Width = base.Height = value; } }
public override int Height { set { base.Width = base.Height = value; } }
}
// Клиентный код, предполагающий независимость width/height, ломается при подстановке Square.
```
Исправление: не делать Square наследником изменяемого Rectangle; использовать композицию или интерфейс только с Area():
```csharp
interface IShape { int Area(); } // реализация для Rectangle и Square отдельно
```
.........4. Interface Segregation Principle (ISP)
Клиенты не должны зависеть от интерфейсов, которые они не используют — предпочитать несколько узких интерфейсов вместо одного «толстого».
Пример (C#):
```csharp
// Плохой дизайн:
interface IMachine { void Print(); void Scan(); void Fax(); }
// Хороший дизайн:
interface IPrinter { void Print(); }
interface IScanner { void Scan(); }
interface IFax { void Fax(); }
class MultiFunctionPrinter : IPrinter, IScanner, IFax { /* реализует всё */ }
class SimplePrinter : IPrinter { /* реализует только печать */ }
```
.........5. Dependency Inversion Principle (DIP)
Высокоуровневые модули не должны зависеть от низкоуровневых — оба должны зависеть от абстракций.
Пример (C#):
```csharp
interface ILogger { void Log(string msg); }
class ConsoleLogger : ILogger { public void Log(string msg) => Console.WriteLine(msg); }
class OrderProcessor {
private readonly ILogger _logger;
public OrderProcessor(ILogger logger) { _logger = logger; }
public void Process() { _logger.Log("processing"); }
}
```
Пояснение: легко подменить реализацию логгера (файл, тест‑мок и т.д.).
Когда строгая приверженность SOLID ведёт к избыточности или противоречиям
- Много мелких классов/интерфейсов (классо‑взрыв) усложняет понимание и настройку (over‑engineering).
- Преждевременная абстракция (YAGNI): затраты на проектирование и поддержание абстракций превышают выгоды.
- Шум от инфраструктуры: большое количество интерфейсов, DI‑конфигурации, фабрик и т.п. увеличивает «бочку» кода и каркас.
- Производительность/латентность: лишняя обертка/прокси/вызовы виртуальных методов в горячих путях.
- Противоречия между принципами: например, чрезмерный SRP (сильное дробление обязанностей) может ухудшить OCP, потому что добавление нового поведения потребует согласования многих мелких классов; реализация DIP через слишком много абстракций создаёт большую связку, которую сложно изменять. LSP может ограничивать OCP, если подклассы не могут удовлетворять контракт базового класса — приходится либо менять базу (нарушая OCP), либо отказываться от наследования.
Практический совет: применять SOLID прагматично — сначала простая реализация, покрытая тестами; рефакторить под конкретные проблемы (частые изменения, тестируемость, повторение кода).
25 Фев в 09:46
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир