# Design Patterns

A design pattern is a generalizable solution to a common problem that we're attempting to address. Design patterns in software development are one case of formalized best practices, specifically around how to structure your code to address specific, recurring design problems in software development.

We include design patterns in a discussion of software development because this is where they tend to be applied: they're more detailed that architecture styles, but more abstract than source code. Often you will find that when you are working through high-level design, and describing the problem to address, you will recognize a problem as similar to something else that you've encountered. A design pattern is a way to formalize that idea of a common, reusable solution, and give you a standard terminology to use when discussing this design with your peers.

Patterns originated with Christopher Alexander, an architect, in 1977 [Alexandar 1977]. Design patterns in software gained popularity with the book Design Patterns: Elements of Reusable Object-Oriented Software, published in 1994 [Gamma 1994]. There have been many books and articles published since then, and during the early 2000s there was a strong push to expand Design Patterns and promote their use.

Design patterns have seen mixed success. Some criticisms levelled:

  • They are not comprehensive and do not reflect all styles of software or all problems encountered.
  • They are old-fashioned and do not reflect current software practices.
  • They add flexibility, at the cost of increased code complexity.

Broad criticisms are likely unfair. While it's true that not all patterns are used, many of them are commonly used in professional practice, and new patterns continue to be identified. Design patterns certainly can add complexity to code, but they also encourage designs that can help avoid subtle bugs later on.

In this section, we'll outline the more common patterns, and indicate where they may be useful. The original set of patterns were subdivided based on the types of problems they addressed.

We'll examine a number of the patterns below.

The original patterns and categories are taken from Eric Gamma et al. 1994. Design Patterns: Elements of Reusable Object-Oriented Software.

Examples and some explanations are from Alexander Shvets. 2019. Dive Into Design Patterns (link).

# Creational Patterns

Creational Patterns control the dynamic creation of objects.

Pattern Description
Abstract Factory Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
Builder Separate the construction of a complex object from its representation, allowing the same construction process to create various representations.
Factory Method Provide an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.
Prototype Specify the kinds of objects to create using a prototypical instance, and create new objects from the 'skeleton' of an existing object, thus boosting performance and keeping memory footprints to a minimum.
Singleton Ensure a class has only one instance, and provide a global point of access to it.

# Example: Builder Pattern

Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.

Imagine that you have a class with a large number of variables that need to be specified when it is created. e.g. a house class, where you might have 15-20 different parameters to take into account, like style, floors, rooms, and so on. How would you model this?

You could create a single class to do this, but you would then need a huge constructor to take into account all the different parameters.

  • You would then need to either provide a long parameter list, or call other methods to help set it up after it was instantiated (in which case you have construction code scattered around).
  • You could create subclasses, but then you have a potentially huge number of subclasses, some of which you may not actually use.

The builder pattern suggests that you put the object construction code into separate objects called builders. The pattern organizes construction into a series of steps. After calling the constructor, you call methods to invoke the steps in the correct order (and the object prevents calls until it is constructed). You only call the steps that you require, which are relevant to what you are building.

Builder pattern
Builder pattern

Even if you never utilize the Builder pattern directly, it's used in a lot of complex Kotlin and Android libraries. e.g. the Alert dialogs in Android.

val dialog = AlertDialog.Builder(this)
	.setTitle("Title")
    .setIcon(R.mipmap.ic_launcher)
    .show()

# Example: Singleton

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

Why is this pattern useful?

  1. Ensure that a class has just a single instance. The most common reason for this is to control access to some shared resource—for example, a database or a file.
  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, to prevent other objects from using the new operator with the Singleton class.
  2. Create a static creation method that acts as a constructor.

In languages like Java, you would express the implementation in this way:

public class Singleton {

    private static Singleton instance = null;
    private Singleton() {
    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

In Kotlin, it's significantly easier.

object Singleton{   
    init {
        println("Singleton class invoked.")
    }
    fun print(){
        println("Print method called")
    }
}

fun main(args: Array<String>) {     
    Singleton.print()
    // echos "Print method called" to the screen
}

The object keyword in Kotlin creates an instance of a generic class., i.e. it's instantiated automatically. Like any other class, you can add properties and methods if you wish.

Singletons are useful for times when you want a single, easily accessible instance of a class. e.g. Database object to access your database, Configuration object to store runtime parameters, and so on. You should also consider it instead of extensively using global variables.

# Structural Patterns

Structural Patterns are about organizing classes to form new structures.

Pattern Description
Adapter, Wrapper Convert the interface of a class into another interface clients expect. An adapter lets classes work together that could not otherwise because of incompatible interfaces.
Bridge Decouple an abstraction from its implementation allowing the two to vary independently.
Composite Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
Decorator Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.
Proxy Provide a surrogate or placeholder for another object to control access to it.

# Example: Adapter

Adapter is a structural design pattern that allows objects with incompatible interfaces to collaborate.

Imagine that you have a data source in XML, but you want to use a charting library that only consumes JSON data. You could try and extend one of those libraries to work with a different type of data, but that's risky and may not even be possible if it's a third-party library.

An adapter is an intermediate component that converts from one interface to another. In this case, it could handle the complexities of converting data between formats. Here's a great example from Shvets (2019):

Adapter converting between data formats
Adapter converting between data formats

The simplest way to implement this is using object composition: the adapter is a class that exposes an interface to the main application (client). The client makes calls using that interface, and the adapter performs necessary actions through the service (which is often a library, or something whose interface you cannot control).

Builder pattern
Builder pattern

  1. The client is the class containing business logic (i.e. an application class that you control).
  2. The client interface describes the interface that you have designed for your application to communicate with that class.
  3. The service is some useful library or service (typically which is closed to you), which you want to leverage.
  4. The adapter is the class that you create to serve as an intermediary between these interfaces.
  5. The client application isn't coupled to the adapter because it works through the client interface.

# Behavioural Patterns

Behavioural Patterns are about identifying common communication patterns between objects.

Pattern Description
Command Encapsulate a request as an object, thereby allowing for the parameterization of clients with different requests, and the queuing or logging of requests. It also allows for the support of undoable operations.
Iterator Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Memento Without violating encapsulation, capture and externalize an object's internal state allowing the object to be restored to this state later.
Observer Define a one-to-many dependency between objects where a state change in one object results in all its dependents being notified and updated automatically.
Strategy Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
Visitor Represent an operation to be performed on the elements of an object structure. Visitor lets a new operation be defined without changing the classes of the elements on which it operates.

# Example: Command

Command is a behavioural design pattern that turns a request into a stand-alone object that contains all information about the request (a command could also be thought of as an action to perform).

Imagine that you are writing a user interface, and you want to support a common action like Save. You might invoke Save from the menu, or a toolbar, or a button. Where do you put the code that actually handles saving the data?

If you attach it to the object that the user is interacting with, then you risk duplicating the code. e.g.

Different objects want to invoke the same code
Different objects want to invoke the same code

The Command pattern suggests that you encapsulate the details of the command that you want executed into a separate request, which is then sent to the business logic layer of the application to process.

Command request
Command request

The command class relationship to other classes:

Command pattern implementation
Command pattern implementation

# Example: Observer (MVC)

Observer is a behavioural design pattern that lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they’re observing. This is also called publish-subscribe.

The object that has some interesting state is often called subject, but since it’s also going to notify other objects about the changes to its state, we’ll call it publisher. All other objects that want to track changes to the publisher’s state are called subscribers, or observers of the state of the publisher.

Subscribers register their interest in the subject, who adds them to an internal subscriber list. When something interest happens, the publisher notifies the subscribers through a provided interface.

Observer
Observer

Observer subscribers being notified
Observer subscribers being notified

The subscribers can then react to the changes.

A modified version of Observer is the Model-View-Controller (MVC) pattern, which puts a third intermediate layer—the Controller—between the Publisher and Subscriber to handle user input. We'l review this further in Building Applications > User Interfaces.