Skip to content

Design Patterns

Main concepts behind design patterns

I’ve been using refactoring.guru/design-patterns as a refence for this article.

Design patterns are typical solutions to commonly occurring problems in software design.

They are like pre-made blueprints that you can customize to solve a recurring design problem in your code.

Design patterns can be categorized by their intent and divided into three groups:

  1. Creational patterns
  2. Structural patterns
  3. Behavioral patterns

Creational patterns provide object creation mechanisms that increase flexibility and reuse of existing code:

  • Singleton,
  • Factory Method,
  • Abstract Factory,
  • Builder,
  • Prototype

Structural patterns explain how to assemble objects and classes into larger structures, while keeping these structures flexible and efficient;

  • Adapter,
  • Bridge,
  • Composite,
  • Decorator,
  • Facade,
  • Flyweight,
  • Proxy

Behavioral patterns take care of effective communication and the assignment of responsibilities between objects:

  • Chain of Responsibility,
  • Command,
  • Iterator,
  • Mediator,
  • Memento,
  • Observer,
  • State,
  • Strategy,
  • Template Method,
  • Visitor

Creational pattern

Singleton design pattern lets you ensure that a class has only one instance, while providing a global access point to this instance.

The Singleton pattern solves two problems:

  1. Ensure that a class has just a single instance,
  2. Provide a global access point to that instance.

Just like a global variable, the Singleton pattern lets you access some object from anywhere in the program. However, it also protects that instance from being overwritten by other code.

All implementations of the Singleton have these two steps in common:

  1. Make the default constructor private: prevent other objects from using the new operator with the Singleton class.
  2. Create a static creation method that acts as a constructor.

Under the hood, the static method calls the private constructor to create an object and saves it in a static field. All following calls to that method return the cached object. If your code has access to the Singleton class, then it’s able to call the Singleton’s static method. So whenever that method is called, the same object is always returned.

Use the Singleton pattern when a class in your program should have just a single instance available to all clients (i.e. a single database object shared by different parts of the program). Use the Singleton pattern when you need stricter control over global variables.

The steps to implement Singleton pattern are:

  1. Add a private static field to the class for storing the singleton instance.
  2. Declare a public static creation method for getting the singleton instance.
  3. Implement lazy initialization inside the static method. It should create a new object on its first call and put it into the static field. The method should always return that instance on all subsequent calls.
  4. Make the constructor of the class private. The static method of the class will still be able to call the constructor, but not the other objects.
  5. Go over the client code and replace all direct calls to the singleton’s constructor with calls to its static creation method.
Pros
  1. You can be sure that a class has only a single instance.
  2. You gain a global access point to that instance.
  3. The singleton object is initialized only when it's requested for the first time.
Cons
  1. Violates the Single Responsibility Principle: it solves two problems at the time.
  2. It can mask bad design
  3. Requires special treatment in a multithreaded environment so that multiple threads won't create a singleton object several times.
  4. It may be difficult to unit test the client code of the Singleton because many test frameworks rely on inheritance when producing mock objects.

Since the constructor of the singleton class is private and overriding static methods is impossible in most languages, it will be difficult to mock the singleton.