The structure of patterns in software development

Patterns are an important abstraction in modern software development. They offer well-defined terminology, clean documentation, and learning from the best. Well-known books on the subject are “Design Patterns: Elements of Reusable Object-Oriented Software” and “Pattern-Oriented Software Architecture, Volume 1”.

In this post I turn to the structures of the patterns and take a closer look at the steps the authors follow when presenting their patterns. The steps are obviously the same.



Before I go into more detail about the structure of a pattern, I would like to put all readers on the same level of knowledge and start with the definition of a pattern according to Christopher Alexander.

patterns:”Each pattern is a tripartite rule that expresses a relationship between a particular context, a problem, and a solution.”

This means that a pattern describes a generic solution to a design problem that recurs in a specific context.

  • Of link is the design situation.
  • To problem are the forces in this context.
  • that solution is a configuration that balances these forces.

Christopher Alexander uses the three terms “useful”, “useful” and “used” to describe the benefits of patterns.

  • Useful: A pattern must be usable.
  • Useful: A pattern must be tradable.
  • Used: Patterns are discovered but not invented. This rule is called the rule of three: “A pattern can only be called a pattern if it has been applied to a real-world solution at least three times.”

The two books “Design Patterns: Elements of Reusable Object-Oriented Software” and “Pattern-Oriented Software Architecture, Volume 1” are undoubtedly among the most influential books ever written on software development. However, both works also have a somewhat soporific effect. I attribute this effect primarily to the fact that both books present their patterns in 13 monotonously repeated steps.

In order not to fall into the same trap, I try to present the steps from the book “Design Patterns: Elements of Reusable Object-Oriented Software” as briefly and precisely as possible – and apply them directly to the strategy pattern. The purpose of each step is shown in italics. The content not in italics refers to the strategy pattern.

A concise name that is easy to remember.

strategy pattern

An answer to the question: What is the purpose of the pattern?

Define a family of algorithms, encapsulate them in objects, and make them interchangeable at runtime.

Alternative names for the pattern, if known.

Politics

A motivating example of the pattern.

A container of strings can be sorted in several ways. They can be sorted lexicographically, case-independently, vice versa and so on. It would be a nightmare if you had to hardcode your sorting criteria into your sorting algorithm. It is much more flexible to encapsulate the sorting criterion in an object and to configure the sorting algorithm with the object.

Situations where the pattern can be used.

The strategy pattern is valid when

  • many related classes differ only in their behavior.
  • different variants of an algorithm are needed.
  • The algorithms must be transparent to the user.

structure

A graphic representation of the pattern.



Classes and objects that participate in this pattern.

  • Context: Uses a concrete strategy that implements the strategy interface.
  • Strategy: Declare the interface for the different strategies.
  • ConcreteStrategyA, ConcreteStrategyB: Implement the strategy.

cooperation with the participants.

The context and the concrete strategy implement the chosen algorithm. The context guides the client’s request to the concrete strategy used.

What are the advantages and disadvantages of the pattern?

The advantages of the strategy pattern are:

  • Families of related algorithms can be used uniformly.
  • The implementation details are hidden from the user.
  • The algorithms can be exchanged at runtime.

Pattern Implementation Techniques.

  • Define the context and strategy interface.
  • Implement the concrete strategy.
  • The context can receive its arguments at runtime or at compile time as template parameters.

Code snippet to illustrate the implementation of the pattern. Smalltalk and C++ are used in the book.

The strategy pattern is so tightly integrated into Standard Template Library (STL) design that we hardly notice it anymore. In addition, a simple variant of the strategy pattern is often used in STL.

Here are two of many examples:

std::sort can be parameterized with a sorting criterion. The sort criterion must be a binary predicate. Lambdas are perfectly suited for such binary predicates.

// strategySorting.cpp

#include 
#include 
#include 
#include 
#include 

void showMe(const std::vector& myVec) {
    for (const auto& v: myVec) std::cout << v << " ";
    std::cout << "\n\n";
}


int main(){

    std::cout << '\n';

    // initializing with an initializer lists
    std::vector myStrVec = {"Only", "for", "Testing", "Purpose", "!!!!!"};
    showMe(myStrVec);     // Only for Testing Purpose !!!!! 

    // lexicographic sorting
    std::sort(myStrVec.begin(), myStrVec.end());
    showMe(myStrVec);    // !!!!! Only Purpose Testing for 

    // case insensitive first character
    std::sort(myStrVec.begin(), myStrVec.end(), 
              [](const std::string& f, const std::string& s){ return std::tolower(f[0]) < std::tolower(s[0]); });
    showMe(myStrVec);   // !!!!! for Only Purpose Testing 

    // sorting ascending based on the length of the strings
    std::sort(myStrVec.begin(), myStrVec.end(), 
              [](const std::string& f, const std::string& s){ return f.length() < s.length(); });
    showMe(myStrVec);   // for Only !!!!! Purpose Testing 

    // reverse 
    std::sort(myStrVec.begin(), myStrVec.end(), std::greater() );
    showMe(myStrVec);   // for Testing Purpose Only !!!!! 

    std::cout << "\n\n";

}

The program strategySorting.cpp sorts the vector lexicographically, case-insensitively, in increasing order of string length and in reverse order. For reverse sorting I use the predefined function object std::greater. The output of the application shows the program in the source code.

A policy is a generic function or class whose behavior can be configured. There are usually default values ​​for the policy parameters. std::vector and std::unordered_map are examples of implementing policies in C++. Of course, a policy is a strategy that is configured at compile time via template parameters.

template>          // (1)
class vector; 

template,                               // (3)
    class KeyEqual = std::equal_to,                       // (4)
    class allocator = std::allocator>  // (2)
class unordered_map;

This means that each container has a default allocator for its elements set by T (line 1) or off std::pair (line 2) depends. Also features std::unorderd_map via a standard hash function (line 3) and a standard equality function (line 4). The hash function calculates the hash value from the key and the even function takes care of collisions in the buckets.

At least two known examples of use of the pattern.

There are far more use cases of strategies in modern C++.

  • In C++17, about 70 of the STL algorithms can be configured with an execution policy. Here is an overload of std::sort: to see:

template< class ExecutionPolicy, class RandomIt >
void sort( ExecutionPolicy&& policy,
           RandomIt first, RandomIt last );

Thanks to the execution policy, it is possible to sequentially (std::execution::seq), parallel (std::execution::par) or parallel and vectorized (std::execution::par_unseq) to sort.

  • In C++20, most of the classic STL algorithms have a range counterpart. These interval counterparts support additional extension points such as protrusions. I have already explained this in more detail in my article "Projections with Ranges".

Patterns closely related to this pattern.

Strategy objects must be lightweight objects. Therefore, lambda expression is ideal.

In my next article I would like to clarify how a pattern, algorithm or framework differs from each other and also introduce terms like pattern sequences and pattern language.


(Map)

To the home page

Leave a Comment