Jonathan Boccara's blog

Design Patterns VS Design Principles: Chain of responsibility, Command and Interpreter

Published July 26, 2021 - 0 Comments

More than an exact science, designing our code is a craft (there is even a branch of software development that is called software craftsmanship).

To guide us through this craft of designing our code we have guidelines that have been accumulated over the ages (or rather, decades) by software developers.

23 of them have been collected in the hugely popular Design Patterns book, by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides), commonly abbreviated as a group of authors as the GoF.

On the other hand, we’ve also seen the 9 GRASP design principles, explained in detail in Craig Larman’s book Applying UML and Patterns, which we classified this way:

design principles hierarchy

GRASP principles and GoF patterns are related: the GoF patterns are implementations of the GRASP principles, or at least some of them.

Let’s get into the details of individual design patterns, and reflect on which design principle they relate.

By doing this, we’ll get a finer understanding of design patterns and design principles, and we’ll try to include the GoF design patterns in the above diagram.

Hopefully, that will help us take better decisions when it comes to designing our code.

Let’s start by examining the Behavioral design patterns: Chain of responsibility, Command, Interpreter, Iterator, Mediator, Memento, Null Object, Observer, State, Strategy, Template method, Visitor.

Today we focus on the first three: Chain of responsibility, Command and Interpreter.

Chain of responsibility

The design pattern Chain of Responsibility consists in putting in place a sequence of objects that fallback on each other to handle a request.

That is, a client sends a request to the first object of the sequence. If it can handle it, it does. Otherwise, it passes on the request to the second object of the sequence. And so on:

chain of responsibility design pattern

Does this relate to one or more GRASP principles?

One of them seems obvious: Indirection.

Indeed, the client doesn’t (always) interact with the object that will eventually handle its request. So in many cases, the changes in the handlers won’t affect the client.

Note though that if Chain of Responsibility is indeed an Indirection, then there is an aspect of Indirection that we hadn’t considered before: the components of the Chain of Responsibility can be changed dynamically. Until now we had only considered Indirection as a static construction, but why not have it changeable at runtime too?

This suggests that we could make the Chain of Responsibility look more like a tree than a chain, by having several paths of responsibility that would branch off in several directions.

This gives us a new view on Indirection. Or does that rather suggest that Indirection doesn’t encompass Chain of Responsibility? If you have any thoughts on that do let me know in the comments section.

Command

The design pattern Command consists in creating a class to represent the execution of an action, as opposed to having the calling code contain the code of the action.

This resulting class is supposed to be autonomous, in that any caller can invoke it, without passing it additional parameters. It is its constructor that takes all that is needed to perform the operation:

class MyCommand
{
public:
    // constructor 
    void execute();
private:
    // All the stuff needed to perform the action
};

The above code is the Java-like traditional presentation of the Command design pattern, but the Command pattern can take various forms. For example, it can take the form of a lambda:

auto myAction = [stuffToPerformTheAction](){ /* action */ };

One of the benefits of the Command pattern is that the actions become manipulable by themselves: they can be stored, sorted, invoked at a later time, repeatedly invoked, etc.

To me, the Command pattern allows to create a class that revolves around one single focus: executing an action. Seen this way, it is a way to create High Cohesion. And more precisely than this, it is a Pure Fabrication. Indeed, lambdas don’t map to something of the domain, in general.

It can be argued that Command involves Polymorphism as well. The GoF book even suggests to add a base class above the objects that perform the action, with a virtual method execute, in order to have various types of actions behind a unified interface.

This is certainly useful, but my understanding of the pattern is that its essence is about introducing a class to represent the action. Using this class polymorphically is a only a nice addition.

Interpreter

The Interpreter design pattern helps achieving modular design when processing an Abstract Syntax Tree (AST) of a given language.

The AST is the structured representation of an expression in the form of a tree, stemming from the fact that expressions can be made of sub-expressions: the children of a node in the AST are the subparts of the expression represented by that node.

The GoF book takes the example of the language of regular expressions: a given regex can be represented in the form of an AST.

The Interpreter design pattern consists in defining a base class for an expression, with a method called interpret. And then defining one class derived from this base classe for each type of the sub-expression in the language. Each class implements the the method interpret of its base class, potentially by forwarding some of the work to its children in the AST. The nodes of the AST are made of those classes.

interpret can takes a Context as a parameter. The Context can contain something to be matched up or updated with the expression represented by the AST.

In the example of the AST representing a regular expression, the context contains the string to match it up with. For an AST representing C++ code, the context can contain the object code to output based on the traversal of the AST.

The essence of the Interpreter design pattern lies, in my opinion, in Polymorphism. Indeed, the base class allows to build up a tree in a generic way, and the concrete classes perform the job depending on each sub-expression.

Definite categories?

We’ve determined that:

  • Chain of Responsibility is a form of Indirection
  • Command is a form of Pure Fabrication
  • Interpreter is a form of Polymorphism

(and we’ve also had a refresher on those design patterns!)

Is it that straightforward?

Not necessarily. As Craig Larman puts it, most design patterns involve Pure Fabrications anyway.

But in the above analysis, we’ve tried to understand the essence of each design pattern, the value it brings to manage complexity in code, and attach it to a design principle in particular.

Also, this is only my opinion, and you’re welcome to disagree on how to classify those design patterns. Leave a comment!

In a next post, we’ll continue on this analysis with other design patterns, in order to understand better how they relate to design principles too.

You will also like

Don't want to miss out ? Follow:   twitterlinkedinrss
Share this post!Facebooktwitterlinkedin