Design Patterns - Overview

A design pattern is a general, reusable solution to common occurring problems within a given context in software engineering.


Overview

Back in 1994 a software engineering book describing software patterns was published. The book was written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (aka the Gang of Four). It has been influential to the field of software engineering and is regarded as an important source for object-oriented design theory and practice.

A common theme to the design patterns described are:

Inheritance is powerful but if you over-use it, you can run in problems, such as the coffee shop problem.

Why code to an interface? Well, the client remains unaware of the specific objects they use, as long as it adheres to an interface, you can be flexible, in the sense that an interface forces classes to adhere to them (so they must have the defined method signatures from the interface).

Programming to an interface allows for dynamic binding (specifying implementation at run-time) and polymorphism (several objects which implement the same interface).

Design patterns described in the book can be categorised into either Behavioural, Structural or Creational.

Behavioural

Most of these design patterns are specifically concerned with communication between objects.

  • Chain of responsibility: Create a chain of handlers, each handler decides whether to pass the request onto the next handler or to 'handle' the request itself.
  • Command: An invoker accepts a command object via composition and executes it.
  • Interpreter: Say you've got to define several logical expressions, rather than hardcoding, you'd use Interpreter objects which define the expression.
  • Iterator: Accesses the elements of an object sequentially without exposing its underlying representation.
  • Mediator: A mediator object has access to two (or more) object properties and methods, utilising and combining methods to create new ones. Objects are injected via composition.
  • Memento: Provides the ability to restore an object to its previous state by saving a snapshot of an object.
  • Observer: Observer objects can be attached to a subject object, whenever a subject 'changes', the observer classes attached are triggered.
  • State A 'context' object is injected with a state object, when the 'context' object changes the state, the state object changes, thus changing the behaviour of the 'context' object.
  • Strategy: A 'strategy' object is injected at run-time which executes a method, but the behaviour depends on the object injected.
  • Template method: Defines the skeleton of an algorithm as an abstract class, allowing its subclasses to provide concrete behaviour. Easiest pattern ever - simply extend an abstract class to eliminate duplicate code across the sub classes.
  • Visitor: An object accepts another object as a 'visitor', the 'visitor' gains access to this objects methods and properties.
Structural

These concern class and object composition. They use inheritance to compose interfaces and define ways to compose objects to obtain new functionality.

  • Adapter: Allows classes with incompatible interfaces to work together by wrapping its own interface around that of an already existing class.
  • Bridge: An object which doesn't need to be concerned with its own implementation can be injected with an object which handles this.
  • Composite: Composite objects can be attached to other composite objects, meaning a potential tree like structure of execution can be created .
  • Decorator: Dynamically adds/overrides behaviour in an existing method of an object.
  • Facade: Provides a simplified interface to a large body of code.
  • Flyweight: Reduces the cost of creating and manipulating a large number of similar objects.
  • Proxy: Extend a parent class, then call the parent version of a method within the child method and adjust where necessary.
Creational

These patterns create objects dynamically rather than instantiating them directly. This gives the code more flexibility in deciding which objects need to be created for a given case.

  • Abstract factory: For when you need to group object factories that have a common theme.
  • Builder: Constructs complex objects rather than only returning an object.
  • Factory method: Creates objects without specifying the exact class to create.
  • Static Factory: Creates objects via a static method with parameter/s.
  • Prototype: Creates objects by cloning an existing object.
  • Singleton: Restricts object creation for a class to only one instance.