← Назад к вопросам

Как понять что класс не следует принципу единой ответственности

2.3 Middle🔥 202 комментариев
#Архитектура и паттерны

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ключевые признаки нарушения SRP

Принцип единой ответственности (SRP) декларирует: у класса должна быть только одна причина для изменения. Если класс берёт на себя несколько несвязанных обязанностей, изменения в одной области логики вынудят модифицировать его, рискуя сломать другие. Вот как выявить такие нарушения.

1. Класс имеет множество несвязанных публичных методов

Если методы класса решают разные задачи (работа с данными, валидация, форматирование, сетевое взаимодействие), это тревожный сигнал.

// ПЛОХО: Класс нарушает SRP
class UserManager {
    fun saveUserToDb(user: User) { /* ... */ }
    fun validateUser(user: User): Boolean { /* ... */ }
    fun convertUserToJson(user: User): String { /* ... */ }
    fun uploadUserToServer(user: User) { /* ... */ }
    fun sendWelcomeEmail(user: User) { /* ... */ }
}

Здесь UserManager занимается валидацией, сериализацией, работой с БД, сетевыми запросами и рассылкой. Изменение формата JSON или логики отправки email потребует правок в одном классе.

2. Поля класса используются лишь частью методов

Если некоторые поля используются только в подмножестве методов, вероятно, эти методы представляют отдельную ответственность.

// ПЛОХО: Поля address и email используются только в методах доставки
public class OrderProcessor {
    private Order order;
    private String address;
    private String email;
    
    public void calculateTotal() { /* использует только order */ }
    public void applyDiscount() { /* использует только order */ }
    public void validateAddress() { /* использует address */ }
    public void sendShippingNotification() { /* использует email */ }
}

Поля address и email задействованы лишь в логике доставки, что указывает на необходимость выделения класса ShippingService.

3. Класс часто изменяется по разным причинам

При анализе истории коммитов можно заметить, что класс меняется из-за правок в разных модулях системы (например, из-за изменений в API сети и из-за обновления правил валидации).

4. Большой объём класса и низкая связность

Класс с 500+ строками и низкой связностью методов (методы слабо связаны друг с другом) — кандидат на нарушение SRP. Высокая связность предполагает, что методы работают с общими данными для одной цели.

5. Имя класса не отражает его реальные функции

Если имя класса обобщённое (Manager, Processor, Helper), а его методы выполняют разнородные задачи, это индикатор проблемы. Имя класса должно однозначно описывать его зону ответственности.

Практический пример рефакторинга

Исходный класс с нарушением SRP:

class Report {
    fun fetchData(): Data { /* сетевой запрос */ }
    fun parseData(data: Data): List<Item> { /* парсинг */ }
    fun generatePdf(items: List<Item>): Pdf { /* создание PDF */ }
    fun saveToDatabase(items: List<Item>) { /* сохранение в БД */ }
}

После рефакторинга:

class DataFetcher { fun fetch(): Data }
class DataParser { fun parse(data: Data): List<Item> }
class PdfGenerator { fun generate(items: List<Item>): Pdf }
class DatabaseSaver { fun save(items: List<Item>) }

class ReportFacade(
    private val fetcher: DataFetcher,
    private val parser: DataParser,
    private val pdfGen: PdfGenerator,
    private val dbSaver: DatabaseSaver
) {
    fun createReport() {
        val data = fetcher.fetch()
        val items = parser.parse(data)
        pdfGen.generate(items)
        dbSaver.save(items)
    }
}

Преимущества следования SRP

  • Упрощение тестирования: Легко тестировать каждый класс изолированно.
  • Повторное использование: Классы с одной ответственностью чаще пригодны для reuse.
  • Снижение рисков: Изменения локализованы в одном модуле.
  • Улучшение читаемости: Код становится более предсказуемым.

Таким образом, нарушение SRP проявляется в раздутых классах с разнородными методами, частых изменениях по несвязанным причинам и низкой связности. Рефакторинг через выделение отдельных классов делает систему гибче и поддерживаемее.