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?
In Object-Oriented Design, one of the most critical decisions is how to assign responsibilities to classes and objects. GRASP provides a systematic approach to make these decisions based on best practices.
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
Was this helpful?