Как понять что класс не следует принципу единой ответственности
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Ключевые признаки нарушения 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 проявляется в раздутых классах с разнородными методами, частых изменениях по несвязанным причинам и низкой связности. Рефакторинг через выделение отдельных классов делает систему гибче и поддерживаемее.