Design Patterns with Signature-Based Polymorphism: A C++ Approach, Part 2

Radu Braniste continues his discussion of signature-based polymorphism (SBP), a more permissive variation of subtype polymorphism, usually called duck typing. The journey continues by investigating the impact on some well-known patterns such as template, visitor, and chain of responsibility. Standard implementations published or proposed in different contexts are also contrasted with SBP-based ones throughout the article.

Like this article? We recommend

Like this article? We recommend

This series describes an interesting but rarely mentioned technique in a C++
context: signature-based polymorphism (SBP), a more permissive variation of
subtype polymorphism [1], usually called duck typing. Two objects
having nothing in common can share an implicit interface and be commonly
manipulated by such an interface—no inheritance involved. After
introducing the key concepts in the first part of this series [2], Part 2
continues the journey by investigating the impact on some well-known patterns
such as template, visitor, and chain of responsibility [3]. Standard
implementations published or proposed in different contexts will be contrasted
with SBP-based ones throughout this article.

Template Method Pattern Revisited

Due to its relative simplicity, this pattern is a good starting point for our
discussion. The main intent of the pattern is to create the skeleton of an
algorithm by defining its structure (the concept) in a base class, but defer its
realization. The pattern uses inheritance to allow subclasses to (re)define the
behavior. Like all inheritance-based designs, this solution suffers from a lack
of flexibility, coupling the concept with the varying class hierarchy.

But TemplateBase reveals implementation details by exposing unnecessarily the
mechanism used by the template method as an interface. Making the details
private—sometimes called nonvirtual interface idiom (NVI)
[4]—doesn’t help too much from a design perspective. Because of
inheritance, begin() and end() are forever tied to the template method, and
subsequent classes in the hierarchy lack independence. A more flexible design
might use a strategy-based approach:

The template method defers execution to dispatchImpl, which actually hides
the structure of the "algorithm." The concept supported in this
example is any class exposing begin() and end() methods. Assuming that Handler1
is such a class, we can write the following:

Handler1 h1;
ITemplateHandler th(h1);
th();

What we achieved is the flexibility of using any class implementing the
concept without requiring any inheritance relationship. Taking into account that
ITemplateHandler is not a trivial class and reimplementing it for other concepts
might prove tedious, we might want to improve the design and reuse the
boilerplate as much as possible.

There are two possible solutions. The first one keeps the concept external to
the interface via an additional template, like this:

ITemplateHandlerConcept is now 100 percent reusable, and there is no
inheritance at all. ITemplateHandlerConcept is bound to a certain concept at
compile time in a flexible way that probably fits most of the bills.

The same effect can be achieved using the idiom curiously called "The
Curiously Recurring Template Pattern (CRTP)"[5]. CRTP enables you to factor
out common behavior, and coupled with subtype polymorphism creates a very
powerful tool:

CRTP implementation is similar to the canonical Template Method, while
ITemplateHandlerConcept is more in line with the strategy-based implementation.
CRTP doesn’t bring much value in this case, but sometimes it adds more
precision to the design.

And now the final touch: reapplying SBP to further hide the type of the
handler:

ITemplate is a fully reusable class that has only one role: to offer a
unique, nonvariable interface to all types implementing the function operator.
This enables seamless manipulation of nonhomogeneous collections or unrelated
types, for example: