Design patterns

From bibbleWiki
Jump to navigation Jump to search

Creational Patterns

Abstract Factory

Description

Creates an instance of several families of classes. Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

UML

Pattern abstract factory.png

Usage

Abstract Factory is a very central design pattern for Dependency Injection (DI).

AbstractFactory abstractFactory;
        
//creating a brown toy dog
abstractFactory = FactoryProvider.getFactory("Toy");
Animal toy = (Animal) abstractFactory.create("Dog");
        
abstractFactory = FactoryProvider.getFactory("Color");
Color color =(Color) abstractFactory.create("Brown");

Implementation

C#

using System;
 
namespace DoFactory.GangOfFour.Abstract.Structural
{
  /// <summary>

  /// MainApp startup class for Structural

  /// Abstract Factory Design Pattern.

  /// </summary>

  class MainApp

  {
    /// <summary>

    /// Entry point into console application.

    /// </summary>

    public static void Main()
    {
      // Abstract factory #1

      AbstractFactory factory1 = new ConcreteFactory1();
      Client client1 = new Client(factory1);
      client1.Run();
 
      // Abstract factory #2

      AbstractFactory factory2 = new ConcreteFactory2();
      Client client2 = new Client(factory2);
      client2.Run();
 
      // Wait for user input

      Console.ReadKey();
    }
  }
 
  /// <summary>

  /// The 'AbstractFactory' abstract class

  /// </summary>

  abstract class AbstractFactory

  {
    public abstract AbstractProductA CreateProductA();
    public abstract AbstractProductB CreateProductB();
  }
 
 
  /// <summary>

  /// The 'ConcreteFactory1' class

  /// </summary>

  class ConcreteFactory1 : AbstractFactory

  {
    public override AbstractProductA CreateProductA()
    {
      return new ProductA1();
    }
    public override AbstractProductB CreateProductB()
    {
      return new ProductB1();
    }
  }
 
  /// <summary>

  /// The 'ConcreteFactory2' class

  /// </summary>

  class ConcreteFactory2 : AbstractFactory

  {
    public override AbstractProductA CreateProductA()
    {
      return new ProductA2();
    }
    public override AbstractProductB CreateProductB()
    {
      return new ProductB2();
    }
  }
 
  /// <summary>

  /// The 'AbstractProductA' abstract class

  /// </summary>

  abstract class AbstractProductA

  {
  }
 
  /// <summary>

  /// The 'AbstractProductB' abstract class

  /// </summary>

  abstract class AbstractProductB

  {
    public abstract void Interact(AbstractProductA a);
  }
 
 
  /// <summary>

  /// The 'ProductA1' class

  /// </summary>

  class ProductA1 : AbstractProductA

  {
  }
 
  /// <summary>

  /// The 'ProductB1' class

  /// </summary>

  class ProductB1 : AbstractProductB

  {
    public override void Interact(AbstractProductA a)
    {
      Console.WriteLine(this.GetType().Name +
        " interacts with " + a.GetType().Name);
    }
  }
 
  /// <summary>

  /// The 'ProductA2' class

  /// </summary>

  class ProductA2 : AbstractProductA

  {
  }
 
  /// <summary>

  /// The 'ProductB2' class

  /// </summary>

  class ProductB2 : AbstractProductB

  {
    public override void Interact(AbstractProductA a)
    {
      Console.WriteLine(this.GetType().Name +
        " interacts with " + a.GetType().Name);
    }
  }
 
  /// <summary>

  /// The 'Client' class. Interaction environment for the products.

  /// </summary>

  class Client

  {
    private AbstractProductA _abstractProductA;
    private AbstractProductB _abstractProductB;
 
    // Constructor

    public Client(AbstractFactory factory)
    {
      _abstractProductB = factory.CreateProductB();
      _abstractProductA = factory.CreateProductA();
    }
 
    public void Run()
    {
      _abstractProductB.Interact(_abstractProductA);
    }
  }
}

Builder

Description

Separates object construction from its representation. Separate the construction of a complex object from its representation so that the same construction processes can create different representations.

UML

Pattern builder.png

Usage

Builder pattern aims to “Separate the construction of a complex object from its representation so that the same construction process can create different representations.” It is used to construct a complex object step by step and the final step will return the object.

        HouseBuilder iglooBuilder = new IglooHouseBuilder(); 
        CivilEngineer engineer = new CivilEngineer(iglooBuilder); 
  
        engineer.constructHouse(); 
  
        House house = engineer.getHouse();


Implementation

Java

interface HousePlan 
{ 
    public void setBasement(String basement); 
  
    public void setStructure(String structure); 
  
    public void setRoof(String roof); 
  
    public void setInterior(String interior); 
} 
  
class House implements HousePlan 
{ 
  
    private String basement; 
    private String structure; 
    private String roof; 
    private String interior; 
  
    public void setBasement(String basement)  
    { 
        this.basement = basement; 
    } 
  
    public void setStructure(String structure)  
    { 
        this.structure = structure; 
    } 
  
    public void setRoof(String roof)  
    { 
        this.roof = roof; 
    } 
  
    public void setInterior(String interior)  
    { 
        this.interior = interior; 
    } 
  
} 
  
  
interface HouseBuilder 
{ 
  
    public void buildBasement(); 
  
    public void buildStructure(); 
  
    public void bulidRoof(); 
  
    public void buildInterior(); 
  
    public House getHouse(); 
} 
  
class IglooHouseBuilder implements HouseBuilder 
{ 
    private House house; 
  
    public IglooHouseBuilder()  
    { 
        this.house = new House(); 
    } 
  
    public void buildBasement()  
    { 
        house.setBasement("Ice Bars"); 
    } 
  
    public void buildStructure()  
    { 
        house.setStructure("Ice Blocks"); 
    } 
  
    public void buildInterior()  
    { 
        house.setInterior("Ice Carvings"); 
    } 
  
    public void bulidRoof()  
    { 
        house.setRoof("Ice Dome"); 
    } 
  
    public House getHouse()  
    { 
        return this.house; 
    } 
} 
  
class TipiHouseBuilder implements HouseBuilder 
{ 
    private House house; 
  
    public TipiHouseBuilder()  
    { 
        this.house = new House(); 
    } 
  
    public void buildBasement()  
    { 
        house.setBasement("Wooden Poles"); 
    } 
  
    public void buildStructure()  
    { 
        house.setStructure("Wood and Ice"); 
    } 
  
    public void buildInterior()  
    { 
        house.setInterior("Fire Wood"); 
    } 
  
    public void bulidRoof()  
    { 
        house.setRoof("Wood, caribou and seal skins"); 
    } 
  
    public House getHouse()  
    { 
        return this.house; 
    } 
  
} 
  
class CivilEngineer  
{ 
  
    private HouseBuilder houseBuilder; 
  
    public CivilEngineer(HouseBuilder houseBuilder) 
    { 
        this.houseBuilder = houseBuilder; 
    } 
  
    public House getHouse() 
    { 
        return this.houseBuilder.getHouse(); 
    } 
  
    public void constructHouse() 
    { 
        this.houseBuilder.buildBasement(); 
        this.houseBuilder.buildStructure(); 
        this.houseBuilder.bulidRoof(); 
        this.houseBuilder.buildInterior(); 
    } 
} 
  
class Builder 
{ 
    public static void main(String[] args) 
    { 
        HouseBuilder iglooBuilder = new IglooHouseBuilder(); 
        CivilEngineer engineer = new CivilEngineer(iglooBuilder); 
  
        engineer.constructHouse(); 
  
        House house = engineer.getHouse(); 
  
        System.out.println("Builder constructed: "+ house); 
    } 
}

Go

Introduction
  • Director director.go
  • Builder Interface iBuilder.go
  • Concrete Builder 1 normalBuilder.go
  • Concrete Builder 2 iglooBuilder.go
  • Product house.go

Pattern builder2.png

Code

iBuilder

package main

type iBuilder interface {
    setWindowType()
    setDoorType()
    setNumFloor()
    getHouse() house
}

func getBuilder(builderType string) iBuilder {
    if builderType == "normal" {
        return &normalBuilder{}
    }
    if builderType == "igloo" {
        return &iglooBuilder{}
    }
    return nil
}

normalBuilder

package main

type normalBuilder struct {
    windowType string
    doorType   string
    floor      int
}

func newNormalBuilder() *normalBuilder {
    return &normalBuilder{}
}

func (b *normalBuilder) setWindowType() {
    b.windowType = "Wooden Window"
}

func (b *normalBuilder) setDoorType() {
    b.doorType = "Wooden Door"
}

func (b *normalBuilder) setNumFloor() {
    b.floor = 2
}

func (b *normalBuilder) getHouse() house {
    return house{
        doorType:   b.doorType,
        windowType: b.windowType,
        floor:      b.floor,
    }
}

IglooBuilder

package main

type iglooBuilder struct {
    windowType string
    doorType   string
    floor      int
}

func newIglooBuilder() *iglooBuilder {
    return &iglooBuilder{}
}

func (b *iglooBuilder) setWindowType() {
    b.windowType = "Snow Window"
}

func (b *iglooBuilder) setDoorType() {
    b.doorType = "Snow Door"
}

func (b *iglooBuilder) setNumFloor() {
    b.floor = 1
}

func (b *iglooBuilder) getHouse() house {
    return house{
        doorType:   b.doorType,
        windowType: b.windowType,
        floor:      b.floor,
    }
}

House

package main

type house struct {
    windowType string
    doorType   string
    floor      int
}

Director

package main

type director struct {
    builder iBuilder
}

func newDirector(b iBuilder) *director {
    return &director{
        builder: b,
    }
}

func (d *director) setBuilder(b iBuilder) {
    d.builder = b
}

func (d *director) buildHouse() house {
    d.builder.setDoorType()
    d.builder.setWindowType()
    d.builder.setNumFloor()
    return d.builder.getHouse()
}

main

package main

import "fmt"

func main() {
    normalBuilder := getBuilder("normal")
    iglooBuilder := getBuilder("igloo")

    director := newDirector(normalBuilder)
    normalHouse := director.buildHouse()

    fmt.Printf("Normal House Door Type: %s\n", normalHouse.doorType)
    fmt.Printf("Normal House Window Type: %s\n", normalHouse.windowType)
    fmt.Printf("Normal House Num Floor: %d\n", normalHouse.floor)

    director.setBuilder(iglooBuilder)
    iglooHouse := director.buildHouse()

    fmt.Printf("\nIgloo House Door Type: %s\n", iglooHouse.doorType)
    fmt.Printf("Igloo House Window Type: %s\n", iglooHouse.windowType)
    fmt.Printf("Igloo House Num Floor: %d\n", iglooHouse.floor)
}

Factory Method

Description

Creates an instance of several derived classes. Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

UML

Pattern factory.png

Usage

In Factory pattern, we create object without exposing the creation logic to the client and refer to newly created object using a common interface.

 VehicleFactory factory = new ConcreteVehicleFactory();

 IFactory scooter = factory.GetVehicle("Scooter");
 scooter.Drive(10);

 IFactory bike = factory.GetVehicle("Bike");

Implementation

C#

using System;
namespace Factory
{
    /// <summary>
    /// The 'Product' interface
    /// </summary>
    public interface IFactory
    {
        void Drive(int miles);
    }

    /// <summary>
    /// A 'ConcreteProduct' class
    /// </summary>
    public class Scooter : IFactory
    {
        public void Drive(int miles)
        {
            Console.WriteLine("Drive the Scooter : " + miles.ToString() + "km");
        }
    }

    /// <summary>
    /// A 'ConcreteProduct' class
    /// </summary>
    public class Bike : IFactory
    {
        public void Drive(int miles)
        {
            Console.WriteLine("Drive the Bike : " + miles.ToString() + "km");
        }
    }

    /// <summary>
    /// The Creator Abstract Class
    /// </summary>
    public abstract class VehicleFactory
    {
        public abstract IFactory GetVehicle(string Vehicle);

    }

    /// <summary>
    /// A 'ConcreteCreator' class
    /// </summary>
    public class ConcreteVehicleFactory : VehicleFactory
    {
        public override IFactory GetVehicle(string Vehicle)
        {
            switch (Vehicle)
            {
                case "Scooter":
                    return new Scooter();
                case "Bike":
                    return new Bike();
                default:
                    throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", Vehicle));
            }
        }

    }

Prototype

Description

A fully initialized instance to be copied or cloned. Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

UML

Pattern prototype.png

Usage

This pattern provides a way to create types which could be expensive to create in real time. The cache creates a hash of possible types which can be created and getShape provides method to get a new object.

  ShapeCache.loadCache();

  Shape clonedShape1 = (Shape) ShapeCache.getShape("1");
  Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
  Shape clonedShape3 = (Shape) ShapeCache.getShape("3");

Implementation

Java

Base Shape

public abstract class Shape implements Cloneable {
   
   private String id;
   protected String type;
   
   abstract void draw();
   
   public String getType(){
      return type;
   }
   
   public String getId() {
      return id;
   }
   
   public void setId(String id) {
      this.id = id;
   }
   
   public Object clone() {
      Object clone = null;
      
      try {
         clone = super.clone();
         
      } catch (CloneNotSupportedException e) {
         e.printStackTrace();
      }
      
      return clone;
   }
}

Concrete class Rectangle

public class Rectangle extends Shape {

   public Rectangle(){
     type = "Rectangle";
   }

   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}

Concrete class Square

public class Square extends Shape {

   public Square(){
     type = "Square";
   }

   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}

Create a class to get concrete classes from database and store them in a Hashtable.

import java.util.Hashtable;

public class ShapeCache {
	
   private static Hashtable<String, Shape> shapeMap  = new Hashtable<String, Shape>();

   public static Shape getShape(String shapeId) {
      Shape cachedShape = shapeMap.get(shapeId);
      return (Shape) cachedShape.clone();
   }

   // for each shape run database query and create shape
   // shapeMap.put(shapeKey, shape);
   // for example, we are adding three shapes
   
   public static void loadCache() {
      Circle circle = new Circle();
      circle.setId("1");
      shapeMap.put(circle.getId(),circle);

      Square square = new Square();
      square.setId("2");
      shapeMap.put(square.getId(),square);

      Rectangle rectangle = new Rectangle();
      rectangle.setId("3");
      shapeMap.put(rectangle.getId(), rectangle);
   }
}

Singleton

Description

A class of which only a single instance can exist. Ensure a class only has one instance, and provide a global point of access to it.

UML

Pattern singleton.png

Usage

It is used to provide global point of access to the object. In terms of practical use Singleton patterns are used in logging, caches, thread pools, configuration settings, device driver objects. Design pattern is often used in conjunction with Factory design pattern.

Implementation

C#

public sealed class Singleton  
{  
    Singleton()  
    {  
    }  
    private static readonly object padlock = new object();  
    private static Singleton instance = null;  
    public static Singleton Instance  
    {  
        get  
        {  
            lock (padlock)  
            {  
                if (instance == null)  
                {  
                    instance = new Singleton();  
                }  
                return instance;  
            }  
        }  
    }  
}

Go

package singleton

import (
    "sync"
)

type singleton struct {}

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}

Java

// Java program implementing Singleton class // with getInstance() method

class Singleton 
{ 
    // static variable single_instance of type Singleton 
    private static Singleton single_instance = null; 
  
    // variable of type String 
    public String s; 
  
    // private constructor restricted to this class itself 
    private Singleton() 
    { 
        s = "Hello I am a string part of Singleton class"; 
    } 
  
    // static method to create instance of Singleton class 
    public static Singleton getInstance() 
    { 
        if (single_instance == null) 
            single_instance = new Singleton(); 
  
        return single_instance; 
    } 
}

Python

class Singleton:
   __instance = None
   @staticmethod 
   def getInstance():
      """ Static access method. """
      if Singleton.__instance == None:
         Singleton()
      return Singleton.__instance
   def __init__(self):
      """ Virtually private constructor. """
      if Singleton.__instance != None:
         raise Exception("This class is a singleton!")
      else:
         Singleton.__instance = self
s = Singleton()
print s

s = Singleton.getInstance()
print s

s = Singleton.getInstance()
print s

Rust

use ruspiro_singleton::*;

static FOO: Singleton<Foo> = Singleton::new(Foo::new(0));

struct Foo {
    count: u32,
}

impl Foo {
    pub const fn new(initial_count: u32) -> Self {
        Foo {
            count: initial_count,
        }
    }

    pub fn count(&self) -> u32 {
        self.count    
    }

    pub fn add_count(&mut self, value: u32) -> u32 {
        self.count += value;
        self.count
    }
}

Structural Patterns

Adapter

Description

Match interfaces of different classes.Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

UML

Pattern adapter.png

Usage

This can be used on GUIs to allow an object to be displayed, for instance, in a grid control

Implementation

C#

using System;
 
namespace DoFactory.GangOfFour.Adapter.Structural
{
  /// <summary>

  /// MainApp startup class for Structural

  /// Adapter Design Pattern.

  /// </summary>

  class MainApp

  {
    /// <summary>

    /// Entry point into console application.

    /// </summary>

    static void Main()
    {
      // Create adapter and place a request

      Target target = new Adapter();
      target.Request();
 
      // Wait for user

      Console.ReadKey();
    }
  }
 
  /// <summary>

  /// The 'Target' class

  /// </summary>

  class Target

  {
    public virtual void Request()
    {
      Console.WriteLine("Called Target Request()");
    }
  }
 
  /// <summary>

  /// The 'Adapter' class

  /// </summary>

  class Adapter : Target

  {
    private Adaptee _adaptee = new Adaptee();
 
    public override void Request()
    {
      // Possibly do some other work

      //  and then call SpecificRequest

      _adaptee.SpecificRequest();
    }
  }
 
  /// <summary>

  /// The 'Adaptee' class

  /// </summary>

  class Adaptee

  {
    public void SpecificRequest()
    {
      Console.WriteLine("Called SpecificRequest()");
    }
  }
}

Java

This example adapts (converts) the Vlc and Mp4 media to a common interface

public interface MediaPlayer {
   public void play(String audioType, String fileName);
}
public interface AdvancedMediaPlayer {	
   public void playVlc(String fileName);
   public void playMp4(String fileName);
}
public class VlcPlayer implements AdvancedMediaPlayer{
   @Override
   public void playVlc(String fileName) {
      System.out.println("Playing vlc file. Name: "+ fileName);		
   }

   @Override
   public void playMp4(String fileName) {
      //do nothing
   }
}
public class Mp4Player implements AdvancedMediaPlayer{

   @Override
   public void playVlc(String fileName) {
      //do nothing
   }

   @Override
   public void playMp4(String fileName) {
      System.out.println("Playing mp4 file. Name: "+ fileName);		
   }
}

Here is the adapter class which converts the two players to a known interface

public class MediaAdapter implements MediaPlayer {

   AdvancedMediaPlayer advancedMusicPlayer;

   public MediaAdapter(String audioType){
   
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();			
         
      }else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }	
   }

   @Override
   public void play(String audioType, String fileName) {
   
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }
      else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}

Here is the player which uses the adapter

public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 

   @Override
   public void play(String audioType, String fileName) {		

      //inbuilt support to play mp3 music files
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: " + fileName);			
      } 
      
      //mediaAdapter is providing support to play other file formats
      else if(audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")){
         mediaAdapter = new MediaAdapter(audioType);
         mediaAdapter.play(audioType, fileName);
      }
      
      else{
         System.out.println("Invalid media. " + audioType + " format not supported");
      }
   }   
}

Here is the demo

public class AdapterPatternDemo {
   public static void main(String[] args) {
      AudioPlayer audioPlayer = new AudioPlayer();

      audioPlayer.play("mp3", "beyond the horizon.mp3");
      audioPlayer.play("mp4", "alone.mp4");
      audioPlayer.play("vlc", "far far away.vlc");
      audioPlayer.play("avi", "mind me.avi");
   }
}

Bridge

Description

Separates an object’s interface from its implementation. Decouple an abstraction from its implementation so that the two can vary independently.

UML

Pattern bridge.png

Composite

Description

A tree structure of simple and composite objects. Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

UML

Pattern composite.png

Decorator

Description

Add responsibilities to objects dynamically. Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

UML

Pattern decorator.png

Facade

Description

A single class that represents an entire subsystem. Provide a unified interface to a set of interfaces in a system. Facade defines a higher-level interface that makes the subsystem easier to use.

UML

Pattern fascade.png

Flyweight

Description

A fine-grained instance used for efficient sharing. Use sharing to support large numbers of fine-grained objects efficiently. A flyweight is a shared object that can be used in multiple contexts simultaneously. The flyweight acts as an independent object in each context — it’s indistinguishable from an instance of the object that’s not shared.

UML

Pattern flyweight.png

Proxy

Description

An object representing another object. Provide a surrogate or placeholder for another object to control access to it.

UML

Pattern proxy.png

Behavioural Patterns

Chain of Responsibility

Description

A way of passing a request between a chain of objects. Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

UML

Pattern proxy.png

Command

Description

Encapsulate a command request as an object. Encapsulate a request as an object, thereby letting you parameterise clients with different requests, queue or log requests, and support undoable operations.

UML

Pattern command.png

Interpreter

Description

A way to include language elements in a program. Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

UML

Pattern interpreter.png

Iterator

Description

Sequentially access the elements of a collection. Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

UML

Pattern interator.png

Mediator

Description

Defines simplified communication between classes. Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

UML

Pattern mediator.png

Memento

Description

Capture and restore an object's internal state. Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.

UML

Pattern momento.png

Observer

Description

A way of notifying change to a number of classes. Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

UML

Pattern observer.png

State

Description

Alter an object's behaviour when its state changes. Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

UML

Pattern state.png

Strategy

Description

Encapsulates an algorithm inside a class. Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

UML

Pattern strategy.png

Template

Description

Defer the exact steps of an algorithm to a subclass. Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.

UML

Pattern template.png

Visitor

Description

Defines a new operation to a class without change. Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

UML

Pattern visitor.png