Что такое принцип единственной ответственности (Single Responsibility) и как его применять?
Первая буква в SOLID — SRP, принцип единственной ответственности. Формулировка «у класса должна быть одна причина для изменения» мне не очень понятна. Что считать «одной причиной»? Как на практике понять, что класс делает слишком много, и как его правильно разделить? Желательно на примере C#.
2 ответа
SRP (Single Responsibility Principle) — у модуля должна быть только одна причина для изменения. Ключевое слово здесь — «причина для изменения», а не «делает одно действие». Причина = заинтересованная сторона (актор), которая может потребовать изменений.
Классический пример нарушения — класс, который смешивает бизнес-логику, хранение и форматирование:
// Нарушение SRP: три разные причины для изменения
public class Invoice
{
public decimal Total { get; set; }
// 1) причина: меняется бизнес-правило расчёта
public decimal CalculateTax() => Total * 0.2m;
// 2) причина: меняется способ хранения
public void SaveToFile(string path) { /* запись в файл */ }
// 3) причина: меняется формат вывода
public string RenderHtml() => $"<b>{Total}</b>";
}
Здесь бухгалтерия отвечает за налог, DBA — за хранение, а отдел маркетинга — за вёрстку. Три разных актора → три причины → разбиваем:
public class Invoice
{
public decimal Total { get; set; }
}
public class TaxCalculator
{
public decimal CalculateTax(Invoice invoice) => invoice.Total * 0.2m;
}
public class InvoiceRepository
{
public void Save(Invoice invoice, string path) { /* запись */ }
}
public class InvoiceHtmlPresenter
{
public string Render(Invoice invoice) => $"<b>{invoice.Total}</b>";
}
Как понять, что пора делить:
- В описании класса появляется союз «и» («считает налог и сохраняет и рендерит»).
- Класс меняется по запросам разных команд/отделов.
- При правке одного метода ломаются тесты совсем другой функциональности.
Не путайте SRP с «один метод на класс» — это перебор. Класс может иметь много методов, если все они обслуживают одну ответственность.
Мне помогает мысленный тест: «Кто придёт ко мне с просьбой изменить этот класс?». Если потенциальных заказчиков двое и более — класс, скорее всего, нарушает SRP.
Ещё полезно смотреть на причины изменения с точки зрения слоёв: логика расчёта, ввод-вывод (БД/файлы/сеть) и представление почти всегда меняются по разным причинам и в разном темпе. Поэтому их и держат раздельно.
Но осторожно: дробить до бесконечности тоже плохо. Если две вещи всегда меняются вместе — пусть живут в одном классе.