Chapter 6. Design Patterns
This chapter will introduce you to some commonly used design patterns. Here is how the chapter is organized:
We will start with a quick introduction to design patterns, followed by a discussion on some Python language features that help to simplify their implementation.
Next, with the help of a fantasy game theme, we will discuss the following design patterns:
For each pattern, a simple game scenario will demonstrate a practical problem. We will see how the design pattern can help solve this problem.
We will also implement each of these patterns using a Pythonic approach.
There are several known design patterns out there. As outlined earlier, we will discuss only a few. The idea is not to present a new cookbook on patterns, but just to show you how design patterns help solve some commonly encountered problems, and how to implement them in Python. Beyond this book, you can explore other traditional design...
Introduction to design patterns
Let's say that during application development, you stumble upon a problem that pops up again and again. Frustrated, you ask your co-developers or a community for help. Guess what, you are not alone. Many have encountered a similar problem in their code. Luckily, you get a response from someone who has found a solution. This solution seemed to have worked reliably on similar problems. You change your problematic code so that it conforms to the suggested design, and voila! Your problem is resolved!
What we just discussed is a software design pattern. A software design pattern is a tried and tested solution or a strategy that helps us solve a commonly encountered problem in the code. Let's start with the broad categories of design patterns followed by some important design principles.
Note
The Gang of Four book:
Before beginning any discussion on the design patterns in Python, it is worth noting that there is an excellent book you may want on your bookshelf, Design...
Python language and design patterns
Thanks to the high-level built-in language features in Python, many of the formal design patterns are easy to implement. In some cases, the patterns appear so natural to the language that it becomes tough to realize them as formal design patterns. For example, an iterator pattern can be realized by using any iterable object, such as lists, dictionaries, and so on. Let's quickly review such language features or paradigms in this section. It is not an exhaustive list, but we will cover some important aspects.
Tip
The idioms that you are about to read (first-class functions, closures, and so on) might sound onerous. But do not get overwhelmed by these terms! If you are a Python programmer, it is very likely that you have already used many of these features knowingly or unknowingly. If these idioms mean nothing to you at the moment, skip ahead to the next section where we fast forward to an imaginary game scenario. In the upcoming discussion, we will use some...
Structure of the rest of the chapter
Before diving into the discussion on design patterns and their implementation, let's first lay out a strategy for the rest of the discussion. As mentioned before, we will review the strategy pattern, the simple and abstract factory patterns, and the adapter pattern. The discussion on design patterns will be roughly structured as follows:
Start with a formal definition of the pattern
Present an imaginary scenario where a new feature is requested
Talk about the problem encountered in introducing this new feature
Make an attempt to solve this problem, quickly realizing that we need to rethink the design
The solution(s) to the problem using the design pattern
For a few design patterns, we will discuss two approaches to solving the problem. A traditional approach that resembles the one followed in languages like C++, and the other, the Pythonic approach.
Tip
Skip the traditional solution if you are interested only in the Pythonic approach.
The following is a list of...
Fast forward – Attack of the Orcs v6.0.0
Let's fast forward to a future imaginary version of the game!
Tip
An Elf is an imaginary supernatural mythical being. Read the The theme of the book section in Chapter 1, Developing Simple Applications for some references on Elves.
Each game character in this version has an ability...
A strategy design pattern is a behavioral pattern that is used to represent a family of algorithms. An algorithm within such a family is represented as a strategy object. The pattern enables easy switching between different strategies (algorithms) of a particular family. This is generally useful when you want to switch to a different strategy at runtime. We will revisit this definition towards the end of the discussion on strategy pattern.
Strategy scenario – The jump feature
You have introduced a new method, jump()
, in the superclass AbstractGameUnit
. All the classes inherit this method, as shown in the following class diagram:
The fence no longer prevents...
A simple factory is generally not viewed as a formal design pattern, but you will find it quite useful in your day-to-day programming. The understanding we gain at the end of this section will be helpful in the discussion on a more formal pattern called abstract factory design pattern. Let's start with the definition of a simple factory.
A factory encapsulates the instance creation piece. The client code doesn't need to know the logic of instance creation. It just knows that whenever it needs an object of a specific type, the factory is the go-to place. Any class, or function, or class method that is used to construct such objects is often referred to as a factory. A simple factory is something you will use quite often. It is typically considered a better object-oriented technique than a formal design pattern.
Simple factory scenario – The recruit feature