Design Pattern Evangelist Blog

Smart pointers about software design

Specification Design Pattern

Allow a Client to select or filter objects with specific attribute property values as specified by the Client.


Specification Sign

Introduction

The Specification Design Pattern is the next of the Composable Design Patterns series. It does not reside within the Gang of Four’s (GoF) Design Pattern catalog.

The Specification Design Pattern allows a Client to identify objects via an attribute value based specification defined by the Client. The attribute specification can be simple or complex. There are several use case scenarios featuring specifications, such as:

Specification is similar to the select or query feature in databases. The main distinction is that the objects being considered within Specification are objects and not records in a database.

The Specification Design Pattern will feature several previous design patterns:

Real World Analogies to Specification

Like the previous composable design patterns, Specification is not difficult to implement. It’s an extension of Composite. Its main challenge is comprehension. Here are a few real-world examples to ease one into the Specification concept.

Matchmaker, Matchmaker, Make Me a Match

The musical Fiddler on the Roof features the song Matchmaker sung by Tevye’s three oldest daughters speculating upon whom the local matchmaker might find for their husbands.

Fiddler on the Roof Poster

Here are several lyrics:
Matchmaker, Matchmaker,
Make me a match,
Find me a find,
Catch me a catch
Matchmaker, Matchmaker
Look through your book,
And make me a perfect match
Matchmaker, Matchmaker,
I’ll bring the veil,
You bring the groom,
Slender and pale.
Bring me a ring for I’m longing to be,
The envy of all I see.
For Papa,
Make him a scholar.
For mama,
Make him rich as a king.

For me, well,
I wouldn’t holler
If he were as handsome as anything.

The lyrics define the specification: (build==slender AND complexion==pale AND education==scholar AND wealth==rich) OR (looks==handsome). They want the Matchmaker to look through her list for a groom for those who match this specification. While not in the lyrics, should a new potential groom match the specification, then they would like to be notified as well.

Collectors

The TV show American Pickers featured antique collectors Mike and Frank driving around rural American looking for trash that they could convert into treasures and sell at their antique store in the Midwest.

Junk Barn

The show focused upon the interesting characters they encountered on the road, the items these characters had collected, and Mike and Frank negotiating a price.

These collections often look like a hoarder’s stash stored in a leaning barn about to topple over. Several times the guys would launch themselves onto unstable filth looking for that diamond in the rough. I’m sure they had to keep their tetanus shots up to date.

The treasures they’d find tended to be antique toys, car parts, motorcycle parts, old gas station signs, etc. The collectors often had detailed knowledge of anything pulled from the piles. They could often remember when and where they acquired something and how much they paid for it.

Quite frankly most of the items Mike and Frank gushed over just looked like junk to me. But they knew the specifications for what their customers wanted and what they’d be willing to pay for them.

Google Searches and Alerts, especially Jobs

Most online search engines are a form of Specification. Your search query is a specification, and the search engine will find and return pages that best match that specification. Google will allow you to create an alert for that specification query so that it will send you an email when it finds additional pages that match that specification.

Google’s Job UI/UX is even closer to Specification. Go to: https://www.google.com/search?q=jobs and click on the Jobs banner at the top.

Google Jobs Portal

This is a Google Jobs portal that will let anyone define a Job Specification based upon job title, location, full/part time, keywords, etc. as shown in the provided image. The Specification can be fine-tuned as much as needed, and Google will refresh the job list upon each update. Once you have a Job Specification you like, you can save it as an Alert so that Google will send you an email when it finds new jobs that match your Specification.

Each job searcher can customize his or her own Job Specification. And job searchers are not limited to just one Specification. They can create different Specifications with different criteria.

Design Structure

Specification is an extension of Composite, but with a few enhancements. We have a few steps before we get there.

Problem Description

We have a Client who is interested in a selection of Context objects based upon a Specification defined by the Client. The Specification is passed to a ContextManager which will return those Context objects that satisfy the Specification.

That description was awful. Let me match the Problem Description terms using the examples above:

Problem Description Matchmaker Antiques Google Jobs
Client Young Woman Customers back at the shop A person looking for a job
ContextManager Matchmaker Mike and Frank Google
Context Husband Candidate Antique/Collector Item residing in a leaning barn An online Job opening
Specification (build==slender AND complexion==pale AND education==scholar AND wealth==rich) OR (looks==handsome) Items their customers are interested in Job location, title, salary, etc.

Here’s a UML class diagram for this behavior:

Specification Overview

This is the last time I will show details for Client and ContextManager. It’s too much to repeat in subsequent diagrams.

Strategy

Let’s get some ideas for how we could implement Specification. Let’s start with the Strategy.

We can do quite a bit with Strategy:

Specification via Strategy

Let’s see how the Client creates Specifications. Here are some examples:

ContextManager contextManager; // injected possibly via a Configurer, not shown
...
List<Context> redContexts contextManager.getContextsBy(new ColorSpecification(Color.RED));
List<Context> circleContexts contextManager.getContextsBy(new ShapeSpecification(Shape.CIRCLE));
List<Context> blueSquareContexts contextmanager.getContextsBy(new ColorAndShapeSpecification(Color.BLUE), Shape.SQUARE));
...

Composite

Strategy will work for simple specifications with one attribute, but the ColorAndShapeSpecification is a bit of a concern. It works fine, but it’s not scalable. What if there are multiple specifications with other attributes for Context? What about Color OR Shape? What about NOT? We don’t want to create a new Specification from scratch when we want a new combination of attributes. The number of potential combinations explodes exponentially.

This is where Composite can be useful. This design maintains the previous design, except that it removes the ColorAndShapeSpecification and replaces it with three new composable Specifications. Each of these new Specifications is a composite. These Specification composites have their own specific behavior within the context of the composite structure. Each of these Boolean operation-based composites contains other Specifications where the composite return value is based upon the return values of the Specifications they contain such that:

Here is the design:

Specification via Composite

Specification Example via Composite

The previous Client Specification examples become:

ContextManager contextManager; // injected possibly via a Configurer, not shown
...
List<Context> redContexts contextManager.getContextsBy(new ColorSpecification(Color.RED)); // Unchanged
List<Context> circleContexts contextManager.getContextsBy(new ShapeSpecification(Shape.CIRCLE)); // Unchanged

Specification blueSquareSpecification = new AndSpecification();
blueSquareSpecification.add(new ColorSpecification(Color.BLUE));
blueSquareSpecification.add(new ShapeSpecification(Shape.SQUARE));
List<Context> blueSquareContexts contextmanager.getContextsBy(blueSquareSpecification); // Composed
...

Let’s examine blueSquareSpecification. It’s a BLUE ColorSpecification and a SQUARE ShapeSpecification which are then composed within an AndSpecification, such that a Context will be satisfied when it is both BLUE and SQUARE.

The AndSpecification will iterate both. If either of them returns false, then it will return false. If both return true, then it will return true.

These three Boolean composite Specifications give us almost infinite possibilities in constructing a Specification without having to add new code except when a new Specification leaf class is needed for a new other attribute.

Specification Example via Showtunes

Here’s the composite Specification for the Matchmaker as mentioned in the example above:

Matchmaker matchMaker; // injected possibly via a Configurer, not shown
...
Specification idealHusbandSpecification = new AndSpecification();
idealHusbandSpecification.add(new BuildSpecification(Slender));
idealHusbandSpecification.add(new ComplexionSpecification(Pale));
idealHusbandSpecification.add(new EducationSpecification(Scholar)); // For Papa
idealHusbandSpecification.add(new WealthSpecification(Rich)); // For Mama

Specification husbandSpecification = new OrSpecification();
husbandSpecification.add(idealHusbandSpecification);
husbandSpecification.add(new LooksSpecification(Handsome));

List<Husband> husbandCandidates matchMaker.getContextsBy(husbandSpecification);
...

The composite tree for the Matchmaker Specification would look like this:

Matchmaker Composite Tree

While this violates the specification order in the lyrics, one might wish to reconfigure the specification to be more efficient:

Matchmaker Composite Tree with Optimal Order

My Final Comment, Or My Comment About Final

The leaf Specification classes contain attributes such as Color or Shape. I declared them as final so that they could not be changed. Once a Specification is defined, I don’t want to worry about it being updated in such a way that it exhibits different behaviors. If a new Specification behavior is needed, then a new Specification instance should be created.

I did the same with NotSpecification. The context is slightly different, but it’s still the same intent. I don’t want the ability to change a NotSpecification instance’s behavior by changing its Specification attribute.

The leaf Specification classes and NotSpecification attributes can be declared as final and initialized in their respective constructors.

However, we can’t easily use the same constructor technique with AndSpecification and OrSpecification. If we want the ability to add Specifications individually as I showed in the previous examples, then we have to allow objects of these classes to be updated via add(Specification specification) after they’ve been constructed.

There is a way to achieve finalness with a slightly different technique. I’m going to add a simple 2-state state machine to SpecificationComposite:

Normally, I prefer a separate state machine class, but since this state machine is so simple and localized, I’m going to represent it via the isInitializing boolean attribute to keep track of the state and which actions are permitted based upon that boolean attribute state. I’m using the Template Method to keep the state machine in the common base class. AndSpecification and OrSpecification are only concerned with the satisfiability of the context with specifications. They are not concerned with the management of the specifications.

When an AndSpecification or OrSpecification is created, as many Specifications can be added to them as needed. But once they are activated with an isSatisfied(Context context) call, then they are no longer being initialized. No new Specifications can be added.

Specification with Finals

The leaf Specifications are Value Objects. Once initialized, they cannot be modified. The SpecificationComposite objects are pseudo-Value Objects. Once activated, they cannot be modified.

Leaf objects in the composite tree are immutable. The non-terminal objects will be immutable once activated. The entire composite tree is a pure function. That means that Specification, and Composite in general, are thread-safe structures. Any number of threads can be calculating satisfiability simultaneously without concern of affecting each other. State resides within the Context argument.

Use Case

This blog entry is too large to include the Use Case. It will be posted in the next blog.

Specification Pros and Cons

The relative pros and cons of Specification are like those with most of the Composable design patterns. Its flexibility is both a pro and a con.

The implementation for Specification is shockingly small. Almost the entire implementation has been shown in the code snippets above. Unit testing will also be trivial.

The power of Specification resides in giving the Client ability to design their own Specifications. Clients can construct a Specification with almost any Boolean satisfiability expression needed. It could be simple. It could be complex. When they configure a logical mistake, they’ll probably blame you first.

Summary

Specification is not in the GoF as its own concept, but it’s an extension of the Composite structure. It will tend to have more narrow uses than some of the other design patterns, but when you fall into that narrow use case, it’s good to have.

References

Since Specification is not in the GoF design pattern catalog and a bit on the margins of design patterns, there aren’t as many online resources as with other design patterns. Here are a few free resources:

Comments

Previous: Composite Design Pattern - Use Case

Next: Specification Design Pattern – Use Case

Home: Design Pattern Evangelist Blog