Understanding responsibilities is key to good object-oriented design.
In the past year, I have done a lot of Object Oriented Design (OOD). I have learned that deciding what methods belong where, and how objects should interact carries consequences and should be undertaken seriously. OOD is definitely not magic. There are patterns, which are named and well-known problem/solution pairs, that can be applied in new contexts.
GRASP (General Responsibility Assignment Software Patterns) defines nine basic OOD principles or building blocks in design. You may have heard of the question "Doesn't GRASP describe principles rather than patterns?". One answer is in the words of the Gang of Four authors, from the preface of their Design Patterns book:
One person's pattern is another person's primitive building block.
Rather than focusing on labels, this blogposts will focus on the following subset of the GRASP patterns: Creator, Information Expert, Low Coupling, Controller and High Cohesion. I will provide a short overview of object design with the just mentioned patterns.
One of the first problems, is to consider who is responsible to create object
X? For example, in a Monopoly game use case, who creates a
Square object? Of course, many objects can create a
Square, but what should we chose, and why?
We can say that a
Car object is the creator, but is the right way? I am sure you said no, because this does not appeal to our mental model of the domain.
Car does not support low representational gap (LRG) between how we think of the domain and a straightforward correspondence with software objects. For me, the
Board object can create the
Squares. Why? Because it feels like an intuition that "containers" create the things "contained".
Here is the definition of the Creator pattern:
Problem: Who creates an
Solution: Assign class
B the responsibility to create an instance of class
A if one of these is true:
Bcontains or compositely aggregate instances of
Brecords instances of
Bclosely use instances of
Bhas the initializing information for instances of
Consistent with LRG and the Creator solution, the
Board will create
The pattern Information Expert is used to determine where to delegate responsibilities, like methods, computed fields etcetera. Information Expert is one of the most basic responsibility assignment principles in OOD.
Let me stick with the Monopoly game use case. Suppose we have objects that need to be able to reference a particular
Square, given its name. Given a key, who should be responsible for knowing a
Just like with Creator, of course, any object can be responsible. It seems obvious to assign
Board with this responsibility. However, it is good to know why.
The definition of Information Expert explains why
Board is chosen:
Name: Information Expert
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 fulfil it.
Coupling is a measure of how strongly one element is connected to, has knowledge of, or depends on other elements. When depended-upon elements changes, and there is coupling or dependency, the dependent may be affected. We can describe Low Coupling as follows:
Name: Low Coupling
Problem: How to reduce the impact of change?
Solution: Assign responsibilities so that unnecessary coupling remains low. Use this princible to evaluate alternatives.
So—in other words—we use Low Coupling to evaluate existing desings or to evaluate the choice between new alternatives. We should prefer a design whose coupling is lower than the alternatives.
If an actor clicks on a button, what should the UI objects do? It is bad practise for the UI objects to contain application or business logic. Therefore, once the UI objects pick up a mouse event, they need to delegate the request to domain objects in the domain layer.
Thus, Controller deals with the basic OOD question: how to connect the UI layer to the application logic layer?
The Controller pattern can be defined as follows:
Problem: What first beyond the UI layer receives and coordinates a system operation?
Solution: Assign the responsibility to an object representing one of the following:
Cohesion measures how functionally related the operations of a software element are, and also measures how much work a software element is doing. The High Cohesion pattern attempts to keep objects appropriately focused, manageable and understandable. High Cohesion is generally used in support of Lower Coupling.
For example, we have object
Big has 100 methods and 2,000 source lines of code.
Big is doing a lot more than object
Small with 10 methods and 200 source lines of code. If the 100 methods of
Big have many responsibilities, then
Big has less focus or functional cohesion than
Small. You should prefer a design with higher cohesion.
Name: High Cohesion
Problem: How to keep objects focused, understandable, and manageable, and as a side effect, support Low Coupling?
Solution: Assign responsibilities so that cohesion remains high. Use this to evaluate alternatives.
Most things in this blogpost I have learned recently. So likely some of it is wrong. I appreciate feedback. I will dig deeper into GRASP patterns in later blogposts.
Let me end with a fun fact. Technically, you should write "GRAS Patterns" rather than "GRASP Patterns". But, yeah, the latter sounds better. 👋