Design Patterns

Created: 3/20/2017
Updated: 8/14/2017

Works Cited

  • Gamma, E, Helm, R, Johnson, R, Vlissides, J. Design Patterns. Addison-Wesley, 1995. 151.
  • Wikipedia Contributors. "Design Patterns." Wikipedia, The Free Encyclopedia. Wikipedia, The Free Encyclopedia, 5 April 2017. Web. 5 April 2017.

Creational Patterns

Creational patterns deal with instantiating objects.

Factory

What: An object that creates other objects.
Why: 1) Having a single object handle multiple variations based on its parameters can increase complexity for maintenance. 2) Furthermore, determining which object instance to create may have external dependencies. Use factory methods to create objects without having to specify the exact class instance to decouple the class from external dependencies. A factory method returns either an interface or a child class (of the factory class).

Example:
class Factory { IProduct createProduct(enum externalDependency) { switch (externalDependency) { case ProductOneType: return new ProductOne(); case ProductTwoType: return new ProductTwo(); default: throw new Exception($"Invalid enum: {externalDependency}"); } } } Interface IProduct { ... } class ProductOne : IProduct { ... } class ProductTwo : IProduct { ... }

Builder

What: An object that receives parameters step-by-step and returns a constructed object from the provided parameters.
Why: Having too many parameters can make a method difficult to maintain and use. The builder pattern can be used to pass parameters to create an object over a series of steps. The builder pattern also can be used to avoid the need to have multiple constructors, which may also be problematic for maintenance.

Example:
class FaceBuilder { public FaceBuilder(); void SetEars(Ears ears); void SetEyes(Eyes eyes); void SetMouth(Mouth mouth); void SetNose(Nose nose); Face GetFace(); // returns the Face object consisting of the facial features set through the set methods } FaceBuilder builder = new FaceBuilder(); builder.SetEars(Ears); builder.SetEyes(Eyes); builder.SetMouth(Mouth); builder.SetNose(Nose); Face face = builder.GetFace();

Prototype

What: Use clone method to produce new objects.
Why: The pattern is used to 1) avoid specifying the concrete subclasses of an abstract class object (abstraction principle) and to 2) avoid the cost of using the "new" keyword to create new objects when it is prohibitively expensive.

Example:
abstract class AbstractObject { public abstract AbstractObject ShallowClone(); } class ConcreteObject : AbstractObject { public override AbstractObject ShallowClone() { return (AbstractObject)this.MemberwiseClone(); // shallow copy } }

Singleton

What: A pattern that restricts a program from creating more than one instantiation of a class object. Generally, it is implemented using a single static instance.
Why: The singleton pattern is useful when there is exactly one instance that is needed as it saves on resource allocation. There is an advantage to using the singleton pattern over a static class when abstraction or inheritance is involved.

Example:
// Using lazy initialization public class Singleton { private static Singleton s_instance = null; private static object s_lock = new object(); public static Singleton Instance { get { if (s_instance == null) { lock(s_lock) { if (s_instance == null) s_instance = new Instance(); } } return s_instance; } } }

Structural Patterns

Structural patterns deal with the composition of entities.

Adapter

What: Wraps an existing class and exposes an interface with modifications to the functionality. The adapter encapsulates the interface of the adaptee.
Why: Allows an existing class implementation to be used from another interface. The adapter pattern is often used to get existing classes to work with other classes without having to change their source code. Generally, the adaptee is a data member of the implemented adapter.

Example:
class Adapter { private Adaptee adaptee; public Adapter(Adaptee a) { adaptee = a; } public string AdaptedStringMethod() { return Format(adaptee.StringMethod()); } }

Bridge

What: A bridge is created when an abstraction takes in an interface to handle certain implementations.
Why: Intended to "decouple an abstraction from its implementation so that the two can vary independently." (Design Patterns)

Example:
interface IComponent { void function(); } class ConcreteComponent : IComponent { public void function() { } } interface IAbstraction { void ExecuteFunction(); } class Concretion : IAbstraction { public IComponent component; public Concretion(IComponent component) { this.component = component; } public void ExecuteFunction() { this.component.function(); } }

Composite

What: Composing an object out of a group of objects in a tree-like structure, such that the individual objects and the composition can be treated uniformly.
Why: To simplify working with tree-like structured data where a leaf node and branch may be treated differently.

Example:
interface IComposite { void Print(); } public class Concretebase : IComposite { public void Print() { ... } } public class Composite : IComposite { public void Append(IComposite comp) { } public void Print() { ... } }

Decorator

What: Add behaviors to individual objects without modifying the behavior of the objects internally.
Why: The purpose of a decorator class is to have a single responsibility, such that it provides one decoration to reduce complexity.

Example:
interface IComponent { void Print(); } public class Component : IComponent { public void Print() { ... } } public abstract ComponentDecorator : IComponent { private IComponent component; public ComponentDecorator(IComponent component) { this.component = component; } public void Print() { this.component.Print(); } } public class AddSomething : ComponentDecorator { public AddSomething(IComponent component) : base(component) { } public void Print() { base.Print(); Console.Writeline("AddSomething"); } }

Facade

What: A class that provides a simplified interface to a larger body of code, such as a class library.
Why: To simplify an existing library.

Example:
public class Facade { private WrappedClassA classA = new WrappedClassA(); private WrappedClassB classB = new WrappedClassB(); public void Method1() { // Do something with classA and/or classB } public void Method2() { // Do something with classA and/or classB } }

Flyweight

What: A class that makes use of sharing data as much as possible.
Why: Minimizes memory usage by sharing data with similar objects. A common practice is to "hold shared data in external data structures and pass them to the flyweight objects temporarily when they are used." (Wikipedia)

Example:
interface IComponent { object GetData(); } public class FlyweightObject : IComponent { private static readonly object s_lock = new object(); private static object s_cache = null; public object GetData() { if (s_cache != null) return s_cache; return LoadData(); } private void LoadData() { if (s_cache == null) { lock (s_lock) { if (s_cache == null) s_cache = LoadDataFromDatabase(); } } } }

Proxy

What: A class functioning as a gateway to another class. A proxy is implemented using the same interface as the class it is serving as a proxy for.
Why: To internally handle validation, optimizations, hide information, and do additional house-keeping job.

Example:
interface IComponent { object GetData(); } public class Component : IComponent { private object m_data; public Component(object a_data) { this. m_data = a_data; } public object GetData() { return this.m_data; } } public class ProxyComponent : IComponent { private Component m_component; public ProxyComponent(object a_data) { this. m_component = new Component(a_data); } public object GetData() { object data = this.m_component.GetData(); if (data == null) throw new Exception("data is not initialized"); return data; } }

Behavioral Patterns

Behavioral patterns deal with communication between objects.

Chain-of-responsibility

What: A pattern where processing objects handle tasks they can handle and pass other tasks onto the next processing object.
Why: To loosely couple the objects in a chain. This allows the processing to be chained or arranged in any order.

Example:
public abstract class AbstractProcessor { private AbstractProcessor m_nextProcessor; public AbstractProcessor () { } public string SetNext(AbstractProcessor a_nextProcessor) { this. m_nextProcessor = a_nextProcessor; } public abstract void Process() { if (this.m_nextProcessor != null) this.m_nextProcessor.Process(); } } public class ProcessorA : AbstractProcessor { public ProcessorA() { } public override void Process() { // if (QualifyToProcess) // Process... // else base.Process(); } } ProcessorA a = new ProcessorA(); ProcessorB b = new ProcessorB(); ProcessorC c = new ProcessorC(); a.SetNext(b); b.SetNext(c);

Command

What: A pattern where the client decides the invoker, command, and receiver. The invoker calls the appropriate command when invoked by the client. The command in turn calls the receiver. The receiver then executes.
Why: To loosely couple the invoker, commands, and receivers. This allows the commands and receivers to be easily interchanged and reused.

Client - The caller that determines the receiver, command, and invoker (e.g. web service API).
Invoker - The entity invoking the command (e.g. user, actor, button, keyboard key).
Command - The action/event (e.g. submit request).
Receiver - The entity action is applied to (e.g. actor, request).

Example:
public interface IReceiver { // actions void ExecuteA(); void ExecuteB(); } public class Receiver : IReceiver { public void ExecuteA() { } public void ExecuteB() { } } public interface ICommand { void Execute(); } public class CommandA : ICommand { private IReceiver m_receiver; public CommandA(IReceiver a_receiver) { this. m_receiver = a_receiver; } public void Execute() { this.m_receiver.ExecuteA(); } } public class CommandB : ICommand { private IReceiver m_receiver; public CommandB(IReceiver a_receiver) { this. m_receiver = a_receiver; } public void Execute() { this.m_receiver.ExecuteB(); } } public class Invoker { private ICommand m_commandA; private ICommand m_commandB; public Invoker(ICommand a_commandA, ICommand a_commandB) { this.m_commandA = a_commandA; this.m_commandB = a_commandB; } public void InvokeA() { this.m_commandA.Execute(); } public void InvokeB() { this.m_commandB.Execute(); } } public class Client { public Client() { } public void ExecuteClient() { IReceiver receiver = new Receiver(); ICommand commandA = new CommandA(receiver); ICommand commandB = new CommandB(receiver); Invoker invoker = new Invoker(commandA, commandB); // if match certain condition for A invoker.InvokeA(); // if match certain condition for B invoker.InvokeB(); } }

Interpreter

What: A pattern that uses tokenized data to interpret languages.
Why: To make use of the composite pattern when interpreting a language.

Example:
public interface IExpression { public object Interpret(Dictionary a_variableContext); } public class Evaluator : IExpression { private IExpression expression; public Evaluator(string a_sContent) { // Parse the content Stack stackExpressions = new Stack(); string[] arrTokens = a_sContent.Split(" "); for (int i = 0; i < arrTokens.Length; ++i) { string sToken = arrToken[i]; if (sToken == "+") { IExpression leftOperand = stackExpressions.Pop(); IExpression rightOperand = arrToken[i + 1]; stackExpressions.Push(new Addition(leftOperand, rightOperand)); } else { stackExpressions.Push(new Variable(sToken)); } } expression = stackExpressions.Pop(); } public object Interpret(Dictionary a_variableContext) { return expression.Interpret(a_variableContext); } } public class Variable : IExpression { private string m_sVariableName; public Variable(string a_sVariableName) { this.m_sVariableName = a_sVariableName; } public object Interpret(Dictionary a_variableContext) { return a_variableContext[m_sVariableName]; } } public class Addition : IExpression { private IExpression m_leftOperand; private IExpression m_rightOperand; public Addition(IExpression a_leftOperand, IExpression a_rightOperand) { this.m_leftOperand = a_leftOperand; this.m_rightOperand = a_rightOperand; } public object Interpret(Dictionary a_variableContext) { return Convert.ToInt(this.m_leftOperand.Interpret(a_variableContext)) + Convert.ToInt(this.m_rightOperand.Interpret(a_variableContext)); } }

Iterator

What: A pattern that exposes an interface to access objects in collections sequentially without exposing the underlying implementations of the collections.
Why: To decouple the algorithms from specific collections.

Example:
public interface IEnumerator { object Current { get; } bool MoveNext(); void Reset(); } public class SampleCollection : IEnumerator { private object[] m_arrData; private int m_nCurrIndex; public SampleCollection(object[] a_arrData) { this.m_arrData = a_arrData; this.m_nCurrIndex = 0; } public object Current { get { return this.m_arrData != null && this. m_nCurrIndex < this.m_arrData.Length ? this.m_arrData[this. m_nCurrIndex] ? null; } } public bool MoveNext() { ++this.m_nCurrIndex; } public void Reset() { this.m_nCurrIndex = 0; } }

Mediator

What: A pattern making use of a class object that encapsulates interactions between multiple other classes.
Why: A program often contains multiple classes that interact with each other, which may increase the complexity of the code. The pattern can be used to reduce complexity and loosely couple multiple classes with the callers.

Example:
// Defines interface for colleague interaction public interface IColleague { void Action(); } // Defines interface for mediation public interface IMediator { void Execute(State a_state); } public class Mediator : IMediator { private IColleague[] m_actors; public Mediator(IColleague[] a_actors) { this.m_actors = a_actors; } // Decouple State and IColleague public void Execute(State a_state) { IEnumerable[] sortedActors = this.m_actors.Sort( (a1, a2)=> a_state[a1].Priority.CompareTo(a_state[a2].Priority)); foreach (IColleague actor in this.m_actors) { Status eStatus = a_state[actor].Status; if (eStatus == Status.Active) actor.Action(); } } }

Memento

What: A pattern where a previous state is stored to enable undoing a change.
Why: Enables the ability to capture the internal state of an object without violating encapsulation.

Caretaker - The entity that applies and undo changes to the originator.
Originator - The entity change is applied to.
Memento - A preserved state of the originator.

Example:
public class Memento { public readonly string State; public Memento(string a_sState) { this.State = a_sState; } } public class Originator { public int Data; public Originator() { } private string Serialize() { return this.Data.ToString(); } private static Originator Deserialize(string a_sSerializedData) { Originator originator = new Originator(); originator.Data = Convert.ToInt(a_sSerializedData); return originator; } public Memento GetCurrentState() { return new Memento(this.Serialize()); } public void RestoreState(Memento a_memento) { Originator old = Originator.Deserialize(a_memento.State); this.Data = old.Data; } } public class Caretaker { public static void main(String[] args) { Originator originator = new Originator(); originator.Data = 1; Memento savedData = originator.GetCurrentState(); originator.Data = 2; originator.RestoreState(savedData); } }

Observer

What: A pattern where an object, known as the subject, maintains a list of objects, known as observers, to notify by invoking their methods when a state change occurs.
Why: Enables event-driven architecture.
Caution: The observer pattern has the subject registering and deregistering observers, which may lead to memory leaks if the observers are not deregistered accordingly. This issue is non-existent with the message queue system where the observers can be decoupled from the subject.

Example:
public class Observer { public void Notify(Info a_info) { // handle notification } } public class ObservableSubject { private List m_observers; public ObservableSubject() { this.m_observers = new List< Observer >(); } public void RegisterObserver(Observer observer) { this.m_observers.Add(observer); } public void DeregisterObserver(Observer observer) { this.m_observers.Remove(observer); } public void NotifyObservers(Info a_info) { foreach (Observer observer in this.m_observers) { observer.Notify(a_info); } } }

State

What: A pattern that models states as class objects implementing the state pattern interface. It is an object-oriented representation of a state machine.
Why: Encapsulates the behavior of an object based on its state and avoid monolithic conditional statements stemming from handling the different states.

Example:
public interface IState { void Execute(StateContext a_state); } public class StateA : IState { public StateA() { } public void Execute(StateContext a_state) { if (a_state.HasData) // Execute on a_state data a_state.SetState(nextState); } } public class StateContext { private IState m_state; public StateContext() { this.m_state = new StateA(); } public void Execute() { this.m_state.Execute(this); } public void SetState(IState a_state) { this.m_state = a_state; } }

Strategy

What: A pattern where the behavior of the class object is determined at runtime.
Why: Decouples the behavior from the class object.

Example:
public interface IStrategy { public void Execute(string a_data); } public class StrategyA : IStrategy { public StrategyA() { } public void Execute(string a_data) { // Do something with the data } } public class Client { private IStrategy m_strategy; public Client(IStrategy a_strategy) { this.m_strategy = a_strategy; } public void Execute(string a_data) { this.m_strategy.Execute(a_data); } public void SetStrategy(IStrategy a_strategy) { this.m_strategy = a_strategy; } }

Template Method

What: A pattern where the skeleton of an algorithm is defined, and a subset of steps within the algorithm can be overridden or are implemented by subclasses.
Why: Allows the general structure of an algorithm to be centralized and reused.

Example:
public interface IOperation { void DoStep1(); void DoStep2(); void DoStep3(); } public class Operation : IOperation { public void DoStep1() { Console.Write("Sleep"); } public void DoStep2() { Console.Write("Dance"); } public void DoStep3() { Console.Write("Shower"); } } public class SomeClass { public void TemplateMethod(MoodEnum a_eMood, IOperation a_operation) { while (a_eMood == MoodEnum.Tired) { a_operation.DoStep1(); } if (a_eMood == MoodEnum.Happy) a_operation.DoStep2(); a_operation.DoStep3(); } }

Visitor

What: A pattern where an algorithm is separated from the class and centralized inside of another class.
Why: Allows the ability to extend functionality to a class without modifying the class. This is one way to satisfy the open/closed principle.

Example:
public interface IVisitor { void Visit(InstanceA a_data); void Visit(InstanceB a_data); } public interface IInstance { void Accept(IVisitor a_visitor); } // Functionality extension public class BillingVisitor : IVisitor { public void Visit(InstanceA a_data) { Bill(a_data); } public void Visit(InstanceB a_data) { Bill(a_data); } } public class InstanceA : IInstance { public void Accept(IVisitor a_visitor) { a_visitor.Visit(this); } } public class InstanceB : IInstance { public void Accept(IVisitor a_visitor) { a_visitor.Visit(this); } } public class Program { public static void main(String[] args) { InstanceA instanceA = new InstanceA(); instanceA.Accept(new BillingVisitor()); } }



All content copyright © 2009-2017 Johnny Huynh. All rights reserved.