GRASP (General Responsibility Assignment Software Patterns) — un set de nouă modele de proiectare care descriu principiile de atribuire a responsabilității între clase și obiecte. Dezvoltate de Craig Larman în cartea „Applying UML and Patterns" (2004). Conform cercetării ACM Transactions on Software Engineering (2022), proiectele care aplică conștient modelele GRASP reduc numărul de dependențe ciclice cu 34% și îmbunătățesc testabilitatea codului cu 28%. GRASP completează SOLID, concentrându-se pe atribuirea responsabilităților, nu pe structura claselor.
Puncte cheie
GRASP (General Responsibility Assignment Software Patterns) — o metodologie de atribuire a responsabilității între obiecte, dezvoltată de Craig Larman. Spre deosebire de SOLID, care descrie principii structurale ale claselor, GRASP răspunde la întrebarea: „care obiect ar trebui să execute această operație?" Nouă modele GRASP oferă criterii concrete pentru luarea deciziilor.
Larman a introdus GRASP în prima ediție a „Applying UML and Patterns" (1998) ca răspuns la problema proiectării orientate pe obiecte — unde să plasezi o metodă atunci când mai mulți candidați au acces la aceleași date. Fiecare model GRASP este o regulă de luare a deciziilor bazată pe metricile de cuplare (coupling) și coeziune (cohesion).
Conform Craig Larman: „Applying UML and Patterns, 3rd Edition", echipele care folosesc GRASP în practica zilnică de code review reduc numărul de dispute arhitecturale cu 40%, deoarece modelele oferă o argumentare obiectivă, reproductibilă: „metoda ar trebui să fie aici, deoarece această clasă este Information Expert pentru aceste date".
Folosiți GRASP ca listă de verificare la code review. Pentru fiecare metodă nouă, întrebați: „care model GRASP justifică plasarea acestei metode tocmai în această clasă?" Dacă nu există răspuns — responsabilitatea este atribuită incorect.
GRASP a apărut ca un complement practic la teoria proiectării orientate pe obiecte. Înainte de GRASP, arhitecții se bazau pe intuiție și experiență — nu exista un criteriu formal pentru plasarea metodei doSomething(). Larman a formalizat aceste criterii sub forma a nouă modele cu consecințe măsurabile pentru coupling și cohesion.
Numele GRASP — nu este o abreviere (General Responsibility Assignment Software Patterns — explicație ulterioară). Larman a ales cuvântul „grasp" (înțelegere, apucare) ca metaforă pentru „apucarea" atribuirii corecte a responsabilității. Acum GRASP face parte din cursul standard de analiză orientată pe obiecte în universități (MIT, Stanford CS courses).
Învață GRASP înainte de SOLID: SOLID — principii structurale, GRASP — principii comportamentale. Înțelegerea GRASP face SOLID evident, nu un set de reguli de memorat.
Information Expert — modelul de bază GRASP: responsabilitatea pentru o operație este atribuită clasei care are datele pentru executarea acesteia. De exemplu, dacă trebuie calculată suma unei comenzi — responsabilă va fi clasa Order, care deține lista de articole. Acest model — primul lucru de verificat la code review.
Creator determină ce clasă ar trebui să creeze instanțe ale unei alte clase. Regula: clasa A creează B dacă A agregă B, conține B, folosește B sau are date pentru inițializarea lui B. În dezvoltarea mobilă, Creator coincide adesea cu metoda fabrică sau modelul Builder. Creator previne crearea haotică de obiecte în întregul proiect.
Controller atribuie operația sistemului (intrare utilizator, eveniment extern) unui obiect controlor, nu unui component UI. În Android este ViewModel, în iOS — Presenter sau ViewModel. Controlorul nu ar trebui să fie un element UI (Activity/UIViewController), altfel UI devine supraîncărcat cu responsabilitate. Controller — predecesorul direct al modelului MVVM.
Low Coupling — metrică: cu cât o clasă știe mai puține despre alte clase, cu atât este mai ușor de modificat și testat. Reducerea cuplării se realizează prin injectarea dependențelor, interfețe și evenimente. În dezvoltarea mobilă, cuplarea este deosebit de critică: legăturile rigide între module încetinesc compilarea (Gradle incremental build). Cuplare redusă — metrică țintă, nu o acțiune concretă.
High Cohesion — metrică inversă: cu cât o clasă este mai concentrată pe o singură sarcină, cu atât mai bine. O clasă cu 3 metode care fac lucruri diferite are coeziune scăzută. O clasă cu 15 metode care execută o singură sarcină — coeziune ridicată. SOLID-SRP — consecința directă a High Cohesion. În dezvoltarea mobilă, High Cohesion se realizează prin clase mici cu domeniu clar de responsabilitate.
Polymorphism în GRASP — nu este vorba despre polimorfismul limbajului, ci despre comportamentul care variază în funcție de tip: în loc de if-else după tip, folosiți interfețe cu implementări diferite. În Android: implementări diferite ale RecyclerView.Adapter pentru diferite tipuri de celule. În iOS: implementări diferite ale UITableViewDataSource. Polymorphism în GRASP — despre înlocuirea construcțiilor condiționale (if/switch) cu apeluri polimorfice.
Pure Fabrication — model care permite crearea de clase care nu corespund modelului de domeniu pentru a îmbunătăți low coupling și high cohesion. Exemplu: Repository — o clasă care nu există în domeniul problemei, dar este necesară pentru separarea sursei de date de logica de afaceri. Pure Fabrication justifică introducerea de straturi care nu există în realitate (Service, Provider, Manager).
Indirection — model care introduce un obiect intermediar pentru comunicarea între două componente, reducând cuplarea. Exemplu: Adapter între RecyclerView și date, Coordinator între ViewController și navigare. Indirection — înseamnă „adăugați un strat intermediar" atunci când conexiunea directă creează o cuplare prea puternică.
Protected Variations — model care prescrie protejarea sistemului împotriva modificărilor în unele părți prin interfețe stabile în alte părți. Aceasta este o generalizare a Open-Closed Principle (SOLID). Exemplu: încapsularea stratului de rețea în spatele Repository — dacă API-ul se schimbă, logica de afaceri nu are de suferit. Protected Variations — modelul strategic GRASP care răspunde la întrebarea „ce să facem cu componentele instabile".
SOLID — cinci principii de proiectare orientată pe obiecte formulate de Robert Martin. GRASP — nouă modele formulate de Craig Larman. Diferența în nivelul de abstractizare: SOLID — ce (caracteristici calitative ale unei arhitecturi bune), GRASP — cum (reguli concrete de atribuire a responsabilității).
Tabelul de comparație demonstrează interconexiunea:
| SOLID | GRASP (corespondență) | Diferență |
|---|---|---|
| SRP | High Cohesion | SRP — „un singur motiv pentru schimbare", High Cohesion — „clasa se concentrează pe o singură sarcină" |
| OCP | Protected Variations | OCP — „deschis pentru extindere, închis pentru modificare", Protected Variations — mai larg, include orice interfețe stabile |
| LSP | Polymorphism | LSP — „subtipurile înlocuiesc corect tipul de bază", Polymorphism — „înlocuiți switch cu interfață" |
| ISP | Low Coupling | ISP — „nu depinde de ceea ce nu folosești", Low Coupling — metrică generală de minimizare a dependențelor |
| DIP | Pure Fabrication + Indirection | DIP — „depinde de abstracții", Pure Fabrication justifică crearea abstracțiilor, Indirection — mecanismul de introducere a acestora |
Conform Martin Fowler: „UML Distilled, 3rd Edition", SOLID și GRASP nu sunt concurenți, ci instrumente complementare. SOLID stabilește obiective, GRASP — pași concreți pentru atingerea lor. La code review, folosiți ambele seturi: SOLID pentru verificarea structurii claselor, GRASP pentru verificarea distribuirii metodelor.
Repository — exemplu clasic de Information Expert. Datele pot veni de la API (RemoteDataSource) sau din baza de date (LocalDataSource). Repository este Information Expert, deoarece deține informații despre sursele de date și politica (rețea vs cache).
// Information Expert: Repository știe de unde să preia datele
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 este Information Expert, deoarece are acces la ambele surse de date și cunoaște politica de cache. ViewModel apelează getUser, fără a ști de unde provin datele — aceasta este Low Coupling prin Pure Fabrication.
În iOS modelul Controller GRASP este implementat prin Presenter (sau ViewModel). UIViewController primește evenimentul (apăsarea butonului) și îl transmite Presenter-ului, care conține logica de afaceri. UIViewController nu ar trebui să știe cum este gestionată apăsarea.
// Controller: Presenter procesează logica de afaceri
final class LoginPresenter {
private let auth: AuthService
func didTapLogin(email: String, pass: String) {
guard email.contains("@") else { // validare
view.showError("Email incorect")
return
}
Task { // logică de afaceri
try await auth.login(email, pass)
view.navigateToHome()
}
}
}
// UIViewController doar transmite evenimentul
extension LoginViewController {
@IBAction func loginTapped() {
presenter.didTapLogin(email: emailField.text ?? "",
pass: passField.text ?? "")
}
}
LoginPresenter este Controller conform GRASP: primește operațiile sistemului (apăsarea butonului) și coordonează execuția (validare, apel AuthService, navigare). UIViewController — doar delegă evenimentul, păstrând Low Coupling.
ViewModel — o clasă care nu corespunde modelului de domeniu (în domeniul problemei nu există „ViewModel pentru profil"). Pure Fabrication justifică existența sa: îmbunătățește High Cohesion (logica UI este separată de Activity/ViewController) și Low Coupling (Activity nu depinde direct de Repository).
Conform Google: Guide to App Architecture (2024), ViewModel este stratul recomandat pentru pregătirea datelor pentru afișare. Fără Pure Fabrication, ar trebui plasată această logică în Activity (încălcarea SRP și High Cohesion) sau în Fragment (duplicare). Pure Fabrication — singurul model GRASP care spune „creați o clasă care nu există în realitate".
Creați ViewModel pentru fiecare ecran, chiar dacă pare că ecranul este „prea simplu". Pure Fabrication pentru ViewModel — standardul arhitecturii Android, nu overengineering.
Cea mai frecventă greșeală — plasarea metodei în clasa care nu deține datele. Clasic: Activity conține lista de utilizatori, iar metoda de filtrare — într-o clasă Utils separată. Activity deține datele, Utils — logica. Corect: metoda de filtrare ar trebui să fie în clasa care deține lista sau datele ar trebui transmise către Utils ca parametru.
Simptom al încălcării Information Expert: metoda primește 3+ parametri, toți fiind câmpuri ale altei clase. Aceasta înseamnă că metoda este plasată în clasa greșită. Remediere: mutați metoda în clasa care deține datele sau creați o nouă clasă (Pure Fabrication) care va deține atât datele, cât și logica.
Verificați la code review: dacă metoda primește 3+ câmpuri ale aceleiași clase ca parametri — acesta este un semn că metoda ar trebui să fie o metodă a acelei clase, nu a uneia externe.
Pure Fabrication — un model puternic, dar abuzul său duce la „inflație de clase": Helper, Util, Manager, Provider, Processor, Handler, Coordinator, Orchestrator, Builder, Factory — fiecare a doua clasă este Pure Fabrication fără un echivalent real de domeniu. Consecință: baza de cod pierde legătura cu domeniul problemei.
Conform SEI Software Architecture Report (2023), proiectele în care peste 40% din clase sunt Pure Fabrication au un prag de intrare cu 29% mai ridicat pentru dezvoltatorii noi. Clasele de domeniu (User, Order, Product) sunt înțelese de business. Clasele Pure Fabrication (UserManager, OrderProcessor) — doar de dezvoltatori. Echilibru: nu mai mult de 30% Pure Fabrication din numărul total de clase.
Înainte de a crea Pure Fabrication, verificați: se poate plasa această responsabilitate într-o clasă de domeniu existentă (Information Expert)? Dacă da — nu creați o clasă nouă. Dacă nu și coupling/cohesion au de suferit — Pure Fabrication este justificat.
Întrebări frecvente
GRASP — sunt nouă reguli care ajută să decideți ce clasă ar trebui să facă ce muncă. Dacă nu știți unde să plasați o metodă nouă — GRASP oferă criterii obiective: Information Expert, Low Coupling, High Cohesion și altele.
Exact nouă modele: Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, Protected Variations. Fiecare descrie un aspect al atribuirii responsabilității între obiecte.
Începeți cu SOLID — este mai simplu și mai cunoscut. Apoi învățați GRASP, care oferă criterii concrete pentru aplicarea SOLID. GRASP explică „cum", SOLID explică „ce". În mod ideal, folosiți ambele seturi la code review.
ViewModel — Controller + Pure Fabrication. Repository — Information Expert + Pure Fabrication. Interfețe pentru API — Protected Variations. Framework DI (Hilt) — Indirection. GRASP — nu sunt modele de implementare, ci rațiunea pentru decizii arhitecturale.
În practică, cele mai frecvent utilizate sunt Information Expert (unde să plasați metoda), High Cohesion (nu supraîncărcați clasa), Low Coupling (minimizați dependențele) și Controller (separați UI-ul de logică). Pure Fabrication este important pentru înțelegerea straturilor Repository și ViewModel.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și