GRASP Principles

About

GRASP (General Responsibility Assignment Software Patterns) is a set of nine fundamental principles used in Object-Oriented Design (OOD) to guide responsibility assignment in software systems. These principles help determine which class should handle which responsibility, ensuring a well-structured, maintainable, and scalable design.

Why GRASP?

The 9 GRASP Principles

Principle

Description

1. Information Expert

Assign responsibility to the class that has the most information required to fulfil it.

2. Creator

The class that contains, aggregates, or closely uses another object should create it.

3. Controller

Assign system operations to a controller that handles incoming requests from the UI.

4. Low Coupling

Reduce dependencies between classes to improve maintainability.

5. High Cohesion

Keep related behavior within a single class to ensure clarity and reusability.

6. Polymorphism

Use interfaces or abstract classes to allow different implementations without modifying the calling code.

7. Pure Fabrication

Introduce a new class (not representing a real-world entity) to improve cohesion and reuse (e.g., a Service class).

8. Indirection

Use an intermediary to reduce direct coupling (e.g., a DAO class for database access).

9. Protected Variations

Use abstraction to protect the system from changes (e.g., Strategy Pattern, Factory Pattern).

1. Information Expert

Assign a responsibility to the class that has the necessary information to fulfill it.

Applicability:

  • If an object has direct access to the required data, it should handle the responsibility.

  • Helps to reduce dependencies and keep behavior close to the data.

Example:

A Student object calculates its own GPA instead of an external class doing it.

Encapsulation is maintained: The data and logic stay in the same class.

2. Creator

Assign the responsibility of creating an object to a class that has the most logical reason to do so.

Applicability:

A class should create an instance of another class if:

  • It contains objects of that class.

  • It uses the created object heavily.

  • It has the necessary data to initialize the object.

Example:

A Customer object creates an Order object since it logically owns orders.

3. Controller

Assign the responsibility of handling system events to a dedicated Controller class.

Applicability:

  • When designing the entry point of a system (UI layer, API, service layer).

  • A Controller class should delegate tasks to the relevant domain classes.

Example:

A BankController class manages user transactions instead of the UI directly handling them.

Ensures separation of concerns between UI and business logic.

4. Low Coupling

Reduce dependencies between classes to improve maintainability and flexibility.

Applicability:

  • Avoid making changes in one class that require changes in multiple other classes.

  • Use dependency injection and interfaces instead of hard dependencies.

Example:

Using an interface instead of direct implementation in a service.

Low Coupling allows switching from PayPal to Other without modifying the Order class.

5. High Cohesion

Ensure that a class focuses on a single responsibility and avoids doing unrelated tasks.

Applicability:

  • If a class handles too many responsibilities, break it into smaller classes.

  • Classes should group related functionality together.

Example:

Splitting User and UserLogger classes instead of mixing authentication & logging.

High Cohesion ensures better readability and maintainability.

6. Polymorphism

Use interfaces and abstract classes to allow different implementations to be handled uniformly.

Applicability:

  • When multiple classes share common behaviour but differ in implementation.

  • Enables open-closed principle (adding new behaviour without modifying existing code).

Example:

Multiple payment methods implementing a common interface.

7. Pure Fabrication

Introduce a class that does not represent a real-world object but exists purely for better separation of concerns.

Applicability:

  • When behaviour doesn’t fit naturally into an existing class.

  • To reduce coupling and increase cohesion.

Example:

A Logger class doesn’t represent a real-world entity but handles logging separately.

Keeps logging concerns separate from business logic. Allows adding new payment methods without modifying PaymentProcessor.

8. Indirection

Use an intermediate class to mediate between components to avoid direct coupling.

Applicability:

  • When a mediator is needed to control interactions.

  • Used in event-driven architectures or dependency injection frameworks.

Example:

Using a MessageBus instead of direct communication between modules.

Allows flexibility in handling notifications or event-driven design.

9. Protected Variations

Shield parts of a system from unwanted changes by using abstractions, encapsulation, and interfaces.

Applicability:

  • When system components should be extendable without modification.

  • Helps in following Open-Closed Principle (OCP).

Example:

Using a database interface instead of hardcoding database logic in services.

Now we can switch databases without modifying Application.

Last updated