I want to write several articles based on specific design patterns, but I thought I should first explain what they are.

Not to be confused with Design Principles, Design Patterns are reusable solutions to common problems that arise in software design. It’s that simple. Developers can also use it to help understand decisions made in code. They provide a way to structure code to make it more maintainable, reusable, and scalable.

There are several types of design patterns including creational, structural, and behavioural patterns.

When I’m introduced to a new project my first step is to speak to the developers (if they’re still around) and read the documentation (which hopefully exists) and uncover any particular design patterns. If I find one I’ve never heard of I’ll go read up about it before I look at the code. You’ll find many websites, like Refactoring Guru, that catalogue design patterns.

Once I’m better armed with the knowledge of what to expect in the code, I can then look at the code and better understand what the original developers were planning and looking to achieve. It can help me spot issues and inefficiencies when the pattern was misapplied or in case no pattern was used I might be able to adapt the code to one.

Before we look at a simple example, let’s talk about the different types of patterns.

Creational patterns

Creational design patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. They are great at increasing the flexibility and reusability of existing code.

Some common creational patterns include Singleton, Factory Method, Abstract Factory, Builder, and Prototype. If you’re like me you’ve heard about these frequently but might have never known that they were design patterns.

Structural patterns

Structural design patterns are concerned with object composition and how objects can be combined to form larger structures. They provide a way to simplify complex relationships between objects and increase the overall efficiency of the system.

Some common structural patterns include Adapter, Bridge, Composite, Decorator, Facade, and Flyweight. I’ll talk more about some of these patterns in later articles, in particular how they can be used to apply SOLID design principles to your code.

Behavioural patterns

Behavioural design patterns define the ways in which objects interact and communicate with each other. They help to manage the flow of communication between objects, making it easier to understand how objects are related and how they work together.

Some common behavioural patterns include Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, and Visitor. These can be quite complex at times and they are quite numerous, this boils down to the fact that there are so many ways services can communicate and as such, it becomes one of the more common points of failure.

Example of the Singleton design pattern

We use the Singleton design pattern fairly often. It is used to ensure that a class has only one instance and to provide a single point of control for accessing that instance.

public sealed class Singleton
{
    private static Singleton instance = null;
    private static readonly object padlock = new object();

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            lock (padlock)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
                return instance;
            }
        }
    }
}

In this example, the Singleton class implements the singleton restriction by using a private static instance variable to store the single instance of the class, and a public static property to access the instance. The lock statement ensures that the singleton instance is thread-safe.

Anti-patterns

I wanted to mention anti-patterns as you start spotting these when you think in line with design patterns. An anti-pattern is a train of thought or design where a solution seems effective but ultimately becomes ineffective or leads to worse consequences down the line.

A simple example of this is using global variables in your code. At first, it seems like it solves quite a few problems, being able to access that variable from across a namespace but then you realise you’re no longer in control of what that value represents. Another developer might come along and be unaware of why it was made global in the first place. Things tend to become bogged down after that.

I’ve frequently caught myself in that line of thought when I’m trying to apply a design pattern to existing code. It’s a design pattern and should be applied in the design phase already. If your code doesn’t gel well it might be time to consider a different approach (start from scratch).

In conclusion

If you’ve been coding for a while, you’ve probably applied (even if incorrectly) a design pattern. When you read about them it can seem very complex and the language can seem ambiguous but this is simply because these are patterns and as such need to apply to any method of design and any coding language.

As you use them more frequently and read up more about them they’ll become like a second language to you when designing applications, and when you don’t recognise one, there’s no harm in asking someone. I don’t think I’ve ever asked a developer to explain a design pattern to me where my question was met with chagrin. Quite the opposite, it’s usually met with the excitement of someone about to show you something amazing.