GRASP (General Responsibility Assignment Software Patterns) — набор из девяти паттернов проектирования, описывающих принципы распределения ответственности между классами и объектами. Разработаны Крейгом Ларманом в книге «Applying UML and Patterns» (2004). По данным исследования ACM Transactions on Software Engineering (2022), проекты, осознанно применяющие GRASP-паттерны, сокращают количество циклических зависимостей на 34% и улучшают тестируемость кода на 28%. GRASP дополняет SOLID, фокусируясь на назначении обязанностей, а не на структуре классов.
Главное
GRASP (General Responsibility Assignment Software Patterns) — методология распределения ответственности между объектами, разработанная Крейгом Ларманом. В отличие от SOLID, который описывает структурные принципы классов, GRASP отвечает на вопрос: «какой объект должен выполнить эту операцию?» Девять паттернов GRASP дают конкретные критерии для принятия решения.
Ларман ввёл GRASP в первом издании «Applying UML and Patterns» (1998) как ответ на проблему объектно-ориентированного проектирования — где разместить метод, когда несколько кандидатов имеют доступ к одним данным. Каждый паттерн GRASP — это правило принятия решения, основанное на метриках связности (coupling) и целостности (cohesion).
Согласно Craig Larman: «Applying UML and Patterns, 3rd Edition», команды, использующие GRASP в ежедневной практике code review, сокращают количество споров об архитектуре на 40%, потому что паттерны дают объективную, воспроизводимую аргументацию: «метод должен быть здесь, потому что этот класс — Information Expert для этих данных».
Используйте GRASP как чек-лист на code review. Для каждого нового метода задайте вопрос: «какой паттерн GRASP оправдывает размещение этого метода именно в этом классе?» Если ответа нет — ответственность распределена неправильно.
GRASP возник как практическое дополнение к теории объектно-ориентированного проектирования. До GRASP архитекторы опирались на интуицию и опыт — не было формального критерия, где разместить метод doSomething(). Ларман формализовал эти критерии в виде девяти паттернов с измеримыми последствиями для coupling и cohesion.
Название GRASP — не аббревиатура (General Responsibility Assignment Software Patterns — расшифровка задним числом). Ларман выбрал слово «grasp» (схватывание, понимание) как метафору для «схватывания» правильного распределения ответственности. Сейчас GRASP входит в стандартный курс объектно-ориентированного анализа в университетах (MIT, Stanford CS courses).
Изучите GRASP до SOLID: SOLID — структурные принципы, GRASP — поведенческие. Понимание GRASP делает SOLID очевидным, а не набором запоминаемых правил.
Information Expert — базовый паттерн GRASP: ответственность за операцию назначается классу, который имеет данные для её выполнения. Например, если нужно рассчитать сумму заказа — ответственным будет класс Order, владеющий списком позиций. Этот паттерн — первое, что нужно проверить на code review.
Creator определяет, какой класс должен создавать экземпляры другого класса. Правило: класс A создаёт B, если A агрегирует B, содержит B, использует B или имеет данные для инициализации B. В мобильной разработке Creator часто совпадает с фабричным методом или Builder-паттерном. Creator предотвращает хаотичное создание объектов по всему проекту.
Controller назначает системную операцию (ввод пользователя, внешнее событие) объекту-контроллеру, а не UI-компоненту. В Android это ViewModel, в iOS — Presenter или ViewModel. Контроллер не должен быть UI-элементом (Activity/UIViewController), иначе UI становится перегруженным ответственностью. Controller — прямой предшественник паттерна MVVM.
Low Coupling — метрика: чем меньше класс знает о других классах, тем легче его изменять и тестировать. Снижение coupling достигается через внедрение зависимостей, интерфейсы и события. В мобильной разработке coupling особенно критичен: жёсткие связи между модулями замедляют компиляцию (Gradle incremental build). Низкая связность — целевая метрика, а не конкретное действие.
High Cohesion — обратная метрика: чем более сфокусирован класс на одной задаче, тем лучше. Класс с 3 методами, делающими разные вещи, имеет низкую cohesion. Класс с 15 методами, делающими одну задачу — высокую. SOLID-SRP — прямое следствие High Cohesion. В мобильной разработке High Cohesion достигается через небольшие классы с понятной зоной ответственности.
Polymorphism в GRASP — не о языковом полиморфизме, а о поведении, которое варьируется по типам: вместо if-else по type используйте интерфейсы с разными реализациями. В Android: разные реализации RecyclerView.Adapter для разных типов ячеек. В iOS: разные реализации UITableViewDataSource. Polymorphism в GRASP — о замене условных конструкций (if/switch) на полиморфные вызовы.
Pure Fabrication — паттерн, разрешающий создавать классы, не соответствующие доменной модели, для улучшения low coupling и high cohesion. Пример: Repository — класс, которого нет в предметной области, но он нужен для отделения источника данных от бизнес-логики. Pure Fabrication оправдывает введение слоёв, не существующих в реальности (Service, Provider, Manager).
Indirection — паттерн, вводящий промежуточный объект для связи между двумя компонентами, снижая coupling. Пример: Adapter между RecyclerView и данными, Coordinator между ViewController и навигацией. Indirection — это «просто добавьте прослойку», когда прямая связь создаёт слишком сильное зацепление.
Protected Variations — паттерн, предписывающий защищать систему от изменений в одних частях через стабильные интерфейсы в других. Это обобщение Open-Closed Principle (SOLID). Пример: инкапсуляция сетевого слоя за Repository — если API изменится, бизнес-логика не пострадает. Protected Variations — стратегический паттерн GRASP, отвечающий на вопрос «что делать с нестабильными компонентами».
SOLID — пять принципов объектно-ориентированного проектирования, сформулированные Робертом Мартином. GRASP — девять паттернов, сформулированных Крейгом Ларманом. Разница в уровне абстракции: SOLID — что (качественные характеристики хорошей архитектуры), GRASP — как (конкретные правила распределения ответственности).
Таблица сопоставления демонстрирует взаимосвязь:
| SOLID | GRASP (соответствие) | Разница |
|---|---|---|
| SRP | High Cohesion | SRP — «одна причина изменения», High Cohesion — «класс фокусируется на одной задаче» |
| OCP | Protected Variations | OCP — «открыт для расширения, закрыт для изменения», Protected Variations — шире, включает любые стабильные интерфейсы |
| LSP | Polymorphism | LSP — «подтипы заменяют базовый тип корректно», Polymorphism — «замените switch на интерфейс» |
| ISP | Low Coupling | ISP — «не завись от того, что не используешь», Low Coupling — общая метрика минимизации зависимостей |
| DIP | Pure Fabrication + Indirection | DIP — «завись от абстракций», Pure Fabrication оправдывает создание абстракций, Indirection — механизм их внедрения |
По данным Martin Fowler: «UML Distilled, 3rd Edition», SOLID и GRASP — не конкуренты, а взаимодополняющие инструменты. SOLID задаёт цели, GRASP — конкретные шаги для их достижения. На code review используйте оба набора: SOLID для проверки структуры классов, GRASP для проверки распределения методов.
Repository — классический пример Information Expert. Данные могут приходить из API (RemoteDataSource) или из БД (LocalDataSource). Репозиторий — Information Expert, так как он владеет информацией об источниках данных и политике (сеть vs кэш).
// Information Expert: Repository знает, откуда брать данные
class UserRepository(
private val api: UserApi,
private val db: UserDao
) {
suspend fun getUser(id: String): User {
val cached = db.getUser(id)
if (cached != null) return cached
val remote = api.fetchUser(id)
db.insert(remote)
return remote
}
}
UserRepository — Information Expert, потому что он имеет доступ к обоим источникам данных и знает политику кэширования. ViewModel вызывает getUser, не зная, откуда пришли данные — это Low Coupling через Pure Fabrication.
В iOS паттерн Controller GRASP реализуется через Presenter (или ViewModel). UIViewController получает событие (нажатие кнопки) и передаёт его Presenter'у, который содержит бизнес-логику. UIViewController не должен знать, как обрабатывается нажатие.
// Controller: Presenter обрабатывает бизнес-логику
final class LoginPresenter {
private let auth: AuthService
func didTapLogin(email: String, pass: String) {
guard email.contains("@") else { // валидация
view.showError("Некорректный email")
return
}
Task { // бизнес-логика
try await auth.login(email, pass)
view.navigateToHome()
}
}
}
// UIViewController только передаёт событие
extension LoginViewController {
@IBAction func loginTapped() {
presenter.didTapLogin(email: emailField.text ?? "",
pass: passField.text ?? "")
}
}
LoginPresenter — Controller по GRASP: он принимает системные операции (нажатие кнопки) и координирует выполнение (валидация, вызов AuthService, навигация). UIViewController — только делегирует событие, соблюдая Low Coupling.
ViewModel — класс, не соответствующий доменной модели (в предметной области нет «ViewModel для профиля»). Pure Fabrication оправдывает его существование: он улучшает High Cohesion (UI-логика отделена от Activity/ViewController) и Low Coupling (Activity не зависит напрямую от Repository).
Согласно Google: Guide to App Architecture (2024), ViewModel — рекомендованный слой для подготовки данных к отображению. Без Pure Fabrication пришлось бы размещать эту логику в Activity (нарушение SRP и High Cohesion) или во Fragment (дублирование). Pure Fabrication — единственный паттерн GRASP, который говорит «создайте класс, которого нет в реальности».
Создавайте ViewModel для каждого экрана, даже если кажется, что экран «слишком простой». Pure Fabrication для ViewModel — стандарт Android-архитектуры, а не overengineering.
Самая частая ошибка — размещение метода не в том классе, который владеет данными. Классика: Activity содержит список пользователей, а метод фильтрации — в отдельном Utils-классе. Activity владеет данными, Utils — логикой. Правильно: метод фильтрации должен быть в классе, владеющем списком, или данные должны быть переданы в Utils как параметр.
Симптом нарушения Information Expert: метод принимает 3+ параметра, все из которых — поля другого класса. Это значит, что метод размещён не в том классе. Исправление: переместите метод в класс-владелец данных или создайте новый класс (Pure Fabrication), который будет владеть и данными, и логикой.
Проверяйте на code review: если метод принимает 3+ поля одного и того же класса как параметры — это признак, что метод должен быть методом этого класса, а не сторонним.
Pure Fabrication — мощный паттерн, но его злоупотребление ведёт к «классовой инфляции»: Helper, Util, Manager, Provider, Processor, Handler, Coordinator, Orchestrator, Builder, Factory — каждый второй класс — Pure Fabrication без реальной доменной сущности. Последствие: кодовая база теряет связь с предметной областью.
По данным SEI Software Architecture Report (2023), проекты, где более 40% классов — Pure Fabrication, имеют на 29% выше порог входа для новых разработчиков. Доменные классы (User, Order, Product) понятны бизнесу. Pure Fabrication-классы (UserManager, OrderProcessor) — только разработчикам. Баланс: не более 30% Pure Fabrication от общего числа классов.
Перед созданием Pure Fabrication проверьте: можно ли разместить эту ответственность в существующем доменном классе (Information Expert)? Если можно — не создавайте новый класс. Если нельзя и coupling/cohesion страдают — Pure Fabrication оправдан.
Часто задаваемые вопросы
GRASP — это девять правил, которые помогают решить, какой класс должен делать какую работу. Если вы не знаете, куда положить новый метод — GRASP даёт объективные критерии: Information Expert, Low Coupling, High Cohesion и другие.
Ровно девять паттернов: Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, Protected Variations. Каждый описывает один аспект распределения ответственности между объектами.
Начните с SOLID — он проще и шире известен. Затем изучайте GRASP, который даёт конкретные критерии применения SOLID. GRASP объясняет «как», SOLID объясняет «что». В идеале используйте оба набора на code review.
ViewModel — Controller + Pure Fabrication. Repository — Information Expert + Pure Fabrication. Интерфейсы для API — Protected Variations. DI-фреймворк (Hilt) — Indirection. GRASP — не паттерны реализации, а rationale для архитектурных решений.
На практике чаще всего используются Information Expert (куда положить метод), High Cohesion (не перегружай класс), Low Coupling (минимизируй зависимости) и Controller (отдели UI от логики). Pure Fabrication важен для понимания слоёв Repository и ViewModel.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также