General Responsibility Assignment Software Patterns (GRASP)#

The General Responsibility Assignment Software Patterns (GRASP) are a set of guidelines for assigning responsibilities to classes and objects in object-oriented design. These patterns help developers create systems with low coupling and high cohesion, making them easier to maintain, extend, and understand.

Here are some of the key GRASP patterns:

  1. Creator: The Creator pattern (see also Factory Method) suggests that a class should be responsible for creating instances of other classes. This pattern helps ensure that the creation of objects is centralized and encapsulated within a single class, promoting modularity and maintainability.

  • Problem: Who creates object A?

  • Solution: Assign class B the responsibility to create object A if one of these is true (more is better):
    • B “contains” or compositely aggregates A objects.

    • B records instances of A objects.

    • B closely uses A objects.

    • B has the initializing data that will be passed to A when it is created.

    • B is a creator of A.

  1. Information Expert: The Information Expert pattern (also: Information Hiding / Encapsulation) states that a class should be responsible for handling information or performing operations related to that information. This pattern helps identify the class that has the most knowledge about a particular task or concept, ensuring that responsibilities are assigned to the most appropriate class.

  • Problem: What is a basic principle by which to assign responsibilities to objects?

  • Solution: Assign a responsibility to the class that has the information needed to fulfill it.

  1. Controller: The Controller pattern suggests that a class should be responsible for coordinating and delegating tasks within a system. This pattern helps define the flow of control and communication between classes, ensuring that responsibilities are clearly assigned and managed. Related patterns are Command and Facade.

  • Problem: What first object beyond the UI layer receives and coordinates “controls” a system operation?

  • Solution: Assign the responsibility to an object representing one of these choices:
    • A class that is responsible for handling user input- Represents the overall “system”, “root object”, device that the software is running within, or a major subsystem (these are all variations of a facade controller)

    • Represents a use case scenario within which the system operation occurs (a use case or session controller)

  1. Low Coupling: The Low Coupling pattern promotes the design of classes with minimal dependencies on other classes. By reducing the coupling between classes, developers can create systems that are more flexible, modular, and easier to maintain.

  • Problem: How to reduce the impact of change? How to support low dependency and increased reuse?

  • Solution: Assign responsibilities so that (unnecessary) coupling remains low. Use this principle to evaluate alternatives.

  1. High Cohesion: The High Cohesion pattern encourages the grouping of related responsibilities within a single class. By ensuring that a class has a clear

  • Problem: How to keep objects focused, understandable, manageable and as a side effect support Low Coupling?

  • Solution: Assign a responsibility so that cohesion remains high. Use this to evaluate alternatives.

  1. Polymorphism: The Polymorphism pattern suggests that classes should be designed to support multiple forms or behaviors. By using polymorphism, developers can create systems that are more extensible and adaptable to changing requirements. Strongly connected to the Strategy pattern. Favor composition and object composition techniques over class inheritance to achieve more flexible and maintainable code.

  • Problem: How handle alternatives based on type?

  • Solution: When related alternatives or behaviors vary by type (class), assign responsibility for the behavior (using polymorphi operations) to the types for which the behavior varies.

  1. Pure Fabrication: The Pure Fabrication pattern states that a class should be created to handle a specific responsibility that does not naturally belong to any other class. This pattern helps avoid assigning responsibilities to classes that do not have the necessary knowledge or information to perform them. This kind of class is often called a “service” in domain-driven design. Sometimes it is really hard to figure it out where responsibility should be placed. This is why in Domain-Driven Design there is a concept of Domain Service. Domain Services hold logic which are not related with one, particular Entity.

  • Problem: What object should have the responsibility, when you do not want to violate High Cohesion and Low Coupling but solutions offered by other principles are not appropriate?

  • Solution: Assign a highly cohesive set of responsibilities to an artificial or convenience class that does not represent a problem domain concept.

  1. Indirection: The Indirection pattern suggests that classes should communicate with each other through intermediaries or abstractions. By introducing indirection, developers can reduce dependencies between classes and promote loose coupling, making systems more flexible and maintainable. see also the Mediator pattern.

  • Problem: Where to assign a responsibility to avoid direct coupling between two or more things?

  • Solution: Assign the responsibility to an intermediate object to mediate between other components or services so that they are not directly coupled.

--- Java Example ---
--- Python Example ---
  1. Protected Variations: The Protected Variations pattern promotes the design of classes that encapsulate variations or changes in the system. By isolating variations within specific classes, developers can create systems that are more resilient to change and easier to maintain. See also Open–Closed principle.

  • Problem: How to design objects, subsystems and systems so that the variations or instability in these elements does not have an undesirable impact on other elements?

  • Solution: Identify points of predicted variation or instability, assign responsibilities to create a stable interface around them.

By applying the GRASP patterns, developers can create object-oriented systems that are well-structured, maintainable, and extensible. These patterns provide a set of guidelines for assigning responsibilities to classes and objects, helping to create systems that are easier to understand, modify, and maintain.