GRASP

Definition

The GRASP design patterns are a set of design patterns. GRASP stands for General Responsibility Assignment Software Patterns. These patterns, as the name suggests, aim primarily to answer the question: “Who does what?”

Patterns list

Main patterns:

  • Information Expert

  • Creator

  • Controller

  • Low Coupling

  • High Cohesion

Additional patterns:

  • Pure Fabrication

  • Indirection

  • Polymorphism

  • Protected Variations

Information Expert

As our systems grow, we might find that we are putting too much logic into our controllers. This results in what we call “bloated controllers”. Bloated controllers imply tight coupling in our system, which is bad.

The Expert Pattern solves this by encapsulating information about a task into a distinct class. for example:

User-authentication is a common problem. We can have a user that is logging in to have their username and password validated within our system. With just a controller, this might look this:

User Login →Controller →Database

This transaction requires a lot of work on the part of the Controller. Authentication may entail hashing, database look-ups and perhaps other application-specific tasks. We, therefore, introduce an expert: Authentication Module. This module knows precisely how to authenticate a user, and the Controller needs only delegate the authentication request to this module to know that authentication will be handled correctly.

Login Request → Controller → Authentication Module → Database

In this way, the Expert pattern is very much like an expert in the real world.

Creator

The Creator takes the responsibility of creating certain other objects. There are a number of reasons why a class may take the responsibility of creating another. The Creator might have information on how to create a said object, or it might be the class that uses the object most closely.

The Creator Pattern is of course a parent to a whole family of patterns in the Gang of Four book, including the very useful Factory, Prototype and Singleton patterns.

Controller

The Controller is responsible for handling the requests of actors. The Controller is the middle-man between your user clicking “Send” and your back-end making that happen. The Controller knows how to interpret the actions of user interfaces, and how to connect those actions to behaviors in your system. This pattern allows user-interfaces to be separated cleanly from “business objects”, and have both changes independently of one another. Implicit in this is that a system can also support many different user interfaces at once, which is very groovy.

The Controller is also an important idiom in modern web development frameworks, in forming a pillar of the Model-View-Controller architectural pattern. Controllers are used in AngularJS, Ruby on Rails, Sails and more.

Low Coupling

Coupling is how strongly the objects are connected to each other. If the first object depending on the second object, when we make some changes to the first, it affects the dependant also.

Low Coupling – How can we reduce the impact of change in depended upon elements on dependant elements. To achieve low coupling we should assign responsibilities so that coupling remains low. Minimizes the dependency hence making the system maintainable, efficient, and code reusable.

Two elements are coupled, if:

  • One element implements/extends another element.

  • One element has aggregation/composition association with another element.

High cohesion

It is important to have code that is clean. Objects need to be manageable, easy to maintain and have clearly stated properties and objectives. This is High Cohesion which includes defined purposes of classes, ability to reuse code, and keeping responsibility to one unit. High Cohesion, Low Coupling, and clearly defined responsibilities go together. To achieve High Cohesionigh Cohesion, a class should have ONE job. Single responsibility principle from SOLID is similar to high cohesion.

Pure Fabrication

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.

Sometimes it is really hard to figure out where responsibility should be placed. This is why in Domain-Driven Design there is a concept of Domain Service. Domain Services hold logic that is not related with one, particular Entity.

For example, in e-commerce systems, we often have the need to convert one currency to another. Sometimes it is hard to say where this behavior should be placed so the best option is to create a new class and interface. This way we support both High Cohesion (we are only converting currencies) and Low Coupling.

Indirection

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.

Indirection introduces an intermediate unit to communicate between the other units, so that the other units are not directly coupled.

Example: Mediator, Adapter, Facade, Observer.

Indirection supports low coupling but reduces readability and reasoning about the whole system. You don’t know which class handles the command from the Controller definition. This is the trade-off to take into consideration.

Polymorphism

Problem: How handle alternatives based on type? Solution: When related alternatives or behaviors vary by type (class), assign responsibility for the behavior (using polymorphic operations) to the types for which the behavior varies.

How to handle related but varying elements based on element type? Polymorphism guides us in deciding which object is responsible for handling those varying elements.

Polymorphism is a fundamental principle of Object-Oriented Design. In this context, the principle is strongly connected with (among others) Strategy Pattern.

Protected variation

Protected variation is how to avoid the impact of variations of some elements on the other elements. It provides a well-defined interface so that there will be no effect on other units. Provides flexibility and protection from variations and provides a more structured design.

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.

Currently, one of the most important software metrics is the ease of change. As architects and programmers, we must be ready for ever-changing requirements. This is not optional and “nice to have” quality attribute – it is a “must-have” and our duty.

Fortunately, we are armed with a lot of design guidelines, principles, patterns and practices to support changes on different levels of abstraction. Here are some of them (already beyond the GRASP):

As iterative software development process is more suitable today because even we are forced to change something once, we can draw conclusions and be prepared for future changes at a lower cost.

Last updated

Was this helpful?