Design principles GRASP

GRASP

Nine questions for deciding which object should own which responsibility.

  • 13 min read
  • 6 chapters
  • Lesson 2 of 4

What you will learn

  1. 01Assigning responsibilities
  2. 02Information Expert and Creator
  3. 03Controller
  4. 04Low coupling and high cohesion
  5. 05Four more tools
  6. 06Using GRASP
01

Assigning responsibilities

Designing objects comes down to one repeated decision: who is responsible for this? GRASP, short for General Responsibility Assignment Software Patterns, is a set of nine rules of thumb for answering it. They matter most when you start modeling a problem like our parking lot, where dozens of small duties must each find a home.

requestdelegatescreatesEntry buttonCLIENToutside worldControllerLLDreceives, delegatesParking lotDBcreates ticketsTicketCHECKknows entry time

Swipe sideways to pan · drag a box to move it

100%
Each duty needs exactly one home.
02

Information Expert and Creator

Information Expert: give a responsibility to the object that already has the information needed. To compute how long a car has stayed, the Ticket knows when it entered, so the Ticket should answer minutesParked(now). Putting that logic elsewhere forces others to reach in and pull data out.

Creator: give the job of creating B to the object that contains B, records B, or closely uses B. The ParkingLot holds the tickets, so the lot creates them.

requestdelegatescreatesEntry buttonCLIENToutside worldControllerLLDreceives, delegatesParking lotDBcreates ticketsTicketCHECKknows entry time

Swipe sideways to pan · drag a box to move it

100%
Creator and Expert: the lot builds tickets, tickets know their time.
03

Controller

Something must receive a request from outside, such as a button press or an API call, and decide what to do. A Controller is the first object past the interface layer that coordinates the work. It should delegate, not do the work itself.

class EntryGate {
  constructor(private lot: ParkingLot) {}
  handle(plate: string, now: number) { return this.lot.enter(plate, now); }
}

A controller that grows its own rules becomes a bloated class. Keep it thin.

requestdelegatescreatesEntry buttonCLIENToutside worldControllerLLDreceives, delegatesParking lotDBcreates ticketsTicketCHECKknows entry time

Swipe sideways to pan · drag a box to move it

100%
The controller only passes the request inward.
04

Low coupling and high cohesion

These are the two yardsticks for judging any assignment.

  • Low coupling: an object should know few others, and only through simple connections. Fewer dependencies mean fewer ripples when something changes.
  • High cohesion: everything in an object should serve one focused purpose.

When two options both work, pick the one with lower coupling and higher cohesion.

05

Four more tools

  • Polymorphism: when behavior varies by type, give each type its own version instead of branching on the type.
  • Pure Fabrication: if no domain object fits a duty without hurting cohesion, invent a class for it, such as a TicketRepository. It does not exist in the real world, and that is fine.
  • Indirection: add a middle object to keep two parts from knowing each other directly.
  • Protected Variations: find the point where change is likely and put a stable interface in front of it.
06

Using GRASP

Ask in order. Who has the data? Who contains or records these things? Who receives the request? Then check the result for coupling and cohesion. Each answer is a tradeoff. Moving a duty to the expert may couple two classes, and a fabrication adds a class to read. Choose the option you will be glad of when the next requirement arrives.