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, оскільки він володіє інформацією про джерела даних і політику (мережа проти кешу).
// 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також