Inevitably throughout your career you will come up across problems that have already been solved in one way or another. This blog is NOT going to describe the common design patterns as stated by the GOF in 1994; there are plenty of good blogs that do that. Alternatively, this post will attempt to address the harder question of the WHEN rather than the WHAT of design patterns … but first let us start by briefly describing the main reasons as to WHY design patterns are important.

The WHY …

There are many ways to skin a cat. Quit often we come up against the same problems over and over again & as developers we have several ways of solving the problem. The purpose of design patterns to establish best practice to solve these common problems by producing solutions that are loosely coupled & with high cohesion…. so why spent time re-inventing the wheel.

Design patterns also help with creating uniformity. Most time spend by developers is spend on reading code; hence we can associate key words with a practical pattern (e.g. Singleton, Factory, Strategy etc.). Reading these keywords, we know right away the intension; or so we should; of the code. Moreover design patterns help us  help to stick to the S.O.L.I.D principles.

The categories …

Loosely speaking design patterns can be grouped into 3 main categories:

  • Creationalthese abstract the instantiation process by deferring the creation to other classes/subclasses.
  • Structural – These patterns describe how classes and objects can be combined to form larger structures.
  • Behaviouralthese are concerned with communication between objects

Thou this grouping is going to drive the reminder of this post there is no hard-fastened way to categories patterns; sometimes patterns are used complementary hence falling into more than one group. An example of which would be when a Singleton used with a Builder. Nevertheless, we will aim to explain the design patterns based on these categories.  Thou taken from a Java perspective the general usage of these definitions can be applied to other programming languages.

Having explained at a hight level the need for design patterns; the hard part will be determining when to apply these patterns. Sadly, there is no easy answer to the “when”; partly this will come with experience BUT having a good understanding of the patterns is a good place to start. A final point must be made is that not all problems will require a pattern. In sometime situations the drawbacks of a pattern outweigh the gains. Again, determining this his will only come with experience.

The When …

Now without further ado the WHEN:

Creational Patterns
Abstract Factory When the creation of a family of objects is delegated to a specific class… Look at factory pattern below.
Factory When the creation of objects is delegated to a specific class. The purpose of the Factory is to provide a mechanism for creating objects without exposing the object’s concrete classes.
Singleton When only a single instance of an object is needed.

Note: Keep in mind when using this design pattern mocking for testing might prove difficult.

Builder When having multiple constructor arguments. The construction process allows different representation for the object that is been constructed. By default, this definition implies that we are not looking for an immutable object here.
Prototype When a copy is required & the creation of an object is expensive. An example would be an object that loads lots of data from a database.

Note that if the pattern is implemented via the Java Cloneable interface a shallow copy of the object is created meaning referenced types are not copied. No constructor is called when using the clone method; hence any logic added at constructor level is ignored.

Structural Patterns
Adapter When faced with two incompatible interfaces
Bridge When we want a parent abstract class to define the set of basic rules, and the concrete classes to add additional rules.
Composite When having a node-leaf scenario with common functionalities. The aim is to be able to manipulate a single object as you would to a group of them. Client code doesn’t have to know if it’s dealing with a leaf or a node.

Note: Violates the Liskov Substitution principle.

Decorator When needing to add/change specific functionality (behaviour or sate) to an object. New functionality to a particular object without disturbing existing objects.
Façade When there are several interfaces used by the clients that can be grouped into one logic group to reduce complexity. (i.e. removes the need to inject several interfaces into the client hence simplifying client interactions with subsystems without reducing features.
Flyweight When needing to reduce the number of objects to be created. Similar to singleton but contains extrinsic data that can change the object at creation or after. When a client requests an object then it is supplied with either an existing instance or a new one is created & added to the pool.
Proxy When needing to create an intermediary that acts as an interface to another resource, while hiding the underlying complexity of the target component. In many ways this is similar to the decorator but differs in purpose.

Note: there are many different types of proxies; virtual proxy, remote proxy, protection proxy. etc

behavioural Patterns
Chain of Responsibility When several objects are candidates to handle a request without specifying the receiver explicitly.
Command When the object that performs the action is decoupled from the requester. Supports the capture of history of requests (support undo or redo operations).

Note: The Chain of Responsibility pattern forwards requests along a chain, the Command pattern forwards the request to a specific module.

Interpreter When needing to represent domain rules as language sentences; used to define the grammar of a language, mapping the language to a grammar, and the grammar to a hierarchical object-oriented design.
Iterator When requiring a uniform way of accessing elements (both forwards & backwards). Provides a way to access the elements of an aggregated object sequentially via traversing elements though a common interface.
Mediator When needing to reduce communication between multiple objects; this pattern will take responsibility of communication among a group of objects dealing with how & which objects interact with each other.
Memento When it’s necessary to record the state of an object; this pattern captures and externalize an objects internal state so that it can be restored later without breaking encapsulation.
Observer When many objects need to be notified automatically whenever an event occurs; this pattern defines a one-to-many dependency between objects so that when one object changes state all of its dependents are notified.
State When an object states changes at runtime & needing to avoid log chain of if-else or switch statements. This pattern allows an object to alter its behaviour when its internal state changes via decency injection.
Strategy When different variants of an algorithm can apply at runtime; this pattern defines a family of algorithms and applies a rule to which should run.
Template Method When execution skeleton of an algorithm needs to be preserved but the implementation steps can vary. This pattern defines the skeleton of an algorithm while deferring some steps to subclasses. Very common in frameworks where the frameworks control how something gets done leaving the client to decide what implementation to use. (i.e. think Spring auto-wiring overrides)
Visitor When you want to decouple some logical code from the elements you are operating on; this pattern follows the open/close principle adds new functionalities to an existing object structure.

Leave a comment