Software design patterns have gone from something of a phenomenon to requisite knowledge for any competent programmer. Their history is fascinating, though, and rooted in abstractions people noticed after writing and looking at lots and lots of code. Smart people figured out common elements, and then were able to describe them eloquently to the rest of us. Let’s have a look at a few important patterns, including some history.

When I was in high school, I learned C++. Or so I thought. At some point
I got a copy of James Coplien’s Advanced C++ Programming Styles and
Idioms.
I read it, in pieces, over and over. I never came close to
understanding most of it. But I realized that (to make an analogy), although
I had learned the rules of chess, **I had no clue how to play**.

Coplien’s book was one of the first places I saw truly incredible things done
with code, that code wasn’t just a way of expressing a solution to a problem.
Code could also be extensible, easier to modify or maintain, more performant,
more closely model the real world problems you’re dealing with. Most
importantly, code could adhere to a set of best practices – avoiding mistakes
people before you have already solved is crucial. Coplien was one of the
first to recognize and *write down* common idioms he saw in good code.
“Idioms” isn’t quite the right word, because these are larger structural
patterns in software. Coplien attempted to explicitly codify these patterns
using a “problem, motivation, solution” type of approach, an approach later
widely embraced in many fields.

## The Envelope/Letter Pattern

One pattern that has stuck with me through the years is the "Envelope/Letter" pattern. Here, the “envelope” is the class that clients interface with. It holds the interface used externally. The “letter” is an object held by the envelope that provides most of the actual semantics (and code!) for the system.

Here’s a great example Coplien gives in his book. We have a `Number`

type with
several subtypes: perhaps integers, rational numbers, real numbers, complex
numbers. (Here I’ve only done integers and real numbers to keep the code
small.) Among the major issues at hand is this: when we add an integer to
a real number, the result is a real number. How do we maintain a consistent
interface when the results of operations on the types can fundamentally change
the types themselves?

Let’s have a look at the classes themselves:

```
class Real;
class Integer;
class Number {
friend Real;
friend Integer;
public:
Number() {}
virtual Number add(const Number &n) const;
virtual Number realAdd(const Number &) const;
virtual Number intAdd(const Number& n) const;
virtual void print() const;
static Number makeReal(float r);
static Number makeInt(int v);
protected:
unique_ptr<Number> rep;
};
class Real : public Number {
friend Integer;
friend Number;
float val;
Real(float r) : val(r) {}
virtual Number add(const Number &n) const;
virtual Number realAdd(const Number &) const;
virtual Number intAdd(const Number& n) const;
virtual void print() const;
};
class Integer : public Number {
friend Real;
friend Number;
int val;
Integer(int n) : val(n) {}
virtual Number add(const Number &n) const;
virtual Number realAdd(const Number &) const;
virtual Number intAdd(const Number& n) const;
virtual void print() const;
};
```

Note that the members of `Real`

and `Integer`

are not public; the only
interface the client sees is that of `Number`

. Furthermore, `Number`

stores
only a pointer to another `Number`

! That will turn out to be one of the
"concrete" classes we define, like `Real`

and `Integers`

, representing real
numbers and integers, respectively.

## Implementation

How about the implementations of these methods? Not so difficult, it turns
out. First, we need a way to make real numbers and integers; this is done
through static methods of the `Number`

class.

```
Number Number::makeReal(float f) {
Number n;
n.rep.reset(new Real(f));
return n;
}
Number Number::makeInt(int v) {
Number n;
n.rep.reset(new Integer(v));
return n;
}
```

See how the pointer in the Number class (the “envelope”) points to the object that actually holds the semantics (the “letter”)? Now that we’ve got this, all we need is ways to add things and coerce them, if necessary, to new types.

```
Number Number::add(const Number& n) const {
return rep->add(n);
}
Number Number::realAdd(const Number& n) const {
return rep->realAdd(n);
}
Number Number::intAdd(const Number& n) const {
return rep->intAdd(n);
}
void Number::print() const {
rep->print();
}
Number Real::add(const Number& n) const {
return n.realAdd(*this);
}
Number Real::realAdd(const Number& n) const {
const Real *rn = dynamic_cast<const Real *>(&n);
return Number::makeReal(this->val + rn->val);
}
Number Real::intAdd(const Number& n) const {
const Integer *it = dynamic_cast<const Integer *>(&n);
return Number::makeReal(this->val+ it->val);
}
void Real::print() const {
cout << "R(" << val << ")";
}
Number Integer::add(const Number& n) const {
return n.intAdd(*this);
}
Number Integer::intAdd(const Number& n) const {
const Integer *it = dynamic_cast<const Integer *>(&n);
return Number::makeInt(this->val+ it->val);
}
Number Integer::realAdd(const Number& n) const {
const Real *rn = dynamic_cast<const Real *>(&n);
return Number::makeReal(this->val + rn->val);
}
void Integer::print() const {
cout << "I(" << val << ")";
}
```

When we add two numbers, the addition is delegated to the `rep`

pointer. This
in turn knows which method to delegate to, and constructs a new `Number`

whose
`rep`

holds a pointer to an object of the appropriate type.

You can see the whole file as a gist here, including tests that show the type of number changes according to it summands.

Now if you’ve seen some design patterns before, this might look familiar… How does it relate to the patterns in the GoF “Design Patterns” book? I’m not 100% sure, but I intend to find out!

Approx. 932 words, plus code