Design patterns

Design patterns are recurring solutions to software design problems you find again and again in real-world application development. Patterns are about design and interaction of objects, as well as providing a communication platform concerning elegant, reusable solutions to commonly encountered programming challenges.

See also here for a detailed explanation of patterns

Creational
Factory pattern
Abstract factory pattern
Builder pattern
Prototype pattern
Singleton

Structural
Decorator pattern
Composite pattern
Facade pattern

Behavioral
Strategy pattern
Chain of responsibility
Visitor pattern

Factory pattern
Provide an interface for creating families of related or dependent objects without specifying their concrete classes. 

 

 

 

UML Diagram factory pattern

UML Diagram

using System;

namespace DoFactory.GangOfFour.Abstract.Structural
{
   // MainApp test application
   class MainApp
   {
      public static void Main()
      {
         // Abstract factory #1
         AbstractFactory factory1 = new ConcreteFactory1();
         Client c1 = new Client(factory1);
         c1.Run();

         // Abstract factory #2
         AbstractFactory factory2 = new ConcreteFactory2();
         Client c2 = new Client(factory2);
         c2.Run();

         // Wait for user input
         Console.Read();
      }
   }

   // "AbstractFactory"
   abstract class AbstractFactory
   {
      public abstract AbstractProductA CreateProductA();
      public abstract AbstractProductB CreateProductB();
   }

   // "ConcreteFactory1"
   class ConcreteFactory1 : AbstractFactory
   {
      public override AbstractProductA CreateProductA()
      {
         return new ProductA1();
      }
      public override AbstractProductB CreateProductB()
      {
         return new ProductB1();
      }
   }

   // "ConcreteFactory2"
   class ConcreteFactory2 : AbstractFactory
   {
      public override AbstractProductA CreateProductA()
      {
         return new ProductA2();
      }
      public override AbstractProductB CreateProductB()
      {
         return new ProductB2();
      }
   }

   // "AbstractProductA"
   abstract class AbstractProductA
   {
   }

   // "AbstractProductB"
   abstract class AbstractProductB
   {
      public abstract void Interact(AbstractProductA a);
   }

   // "ProductA1"
   class ProductA1 : AbstractProductA
   {
   }

   // "ProductB1"
   class ProductB1 : AbstractProductB
   {
      public override void Interact(AbstractProductA a)
      {
         Console.WriteLine(this.GetType().Name +
            " interacts with " + a.GetType().Name);
      }
   }

   // "ProductA2"
   class ProductA2 : AbstractProductA
   {
   }

   // "ProductB2"
   class ProductB2 : AbstractProductB
   {
      public override void Interact(AbstractProductA a)
      {
         Console.WriteLine(this.GetType().Name +
            " interacts with " + a.GetType().Name);
      }
   }

   // "Client" - the interaction environment of the products
   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);
      }
   }
}

Abstract Factory pattern
Separate the construction of a complex object from its representation so that the same construction process can create different representations.

UML Diagram Builder pattern

UML Diagram

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Builder.Structural
{
   // MainApp test application
   public class MainApp
   {
      public static void Main()
      {
         // Create director and builders
         Director director = new Director();

         Builder b1 = new ConcreteBuilder1();
         Builder b2 = new ConcreteBuilder2();

         // Construct two products
         director.Construct(b1);
         Product p1 = b1.GetResult();
         p1.Show();

         director.Construct(b2);
         Product p2 = b2.GetResult();
         p2.Show();

         // Wait for user
         Console.Read();
      }
   }

   // "Director"
   class Director
   {
      // Builder uses a complex series of steps
      public void Construct(Builder builder)
      {
         builder.BuildPartA();
         builder.BuildPartB();
      }
   }

   // "Builder"
   abstract class Builder
   {
      public abstract void BuildPartA();
      public abstract void BuildPartB();
      public abstract Product GetResult();
   }

   // "ConcreteBuilder1"
   class ConcreteBuilder1 : Builder
   {
      private Product product = new Product();

      public override void BuildPartA()
      {
         product.Add("PartA");
      }

      public override void BuildPartB()
      {
         product.Add("PartB");
      }

      public override Product GetResult()
      {
         return product;
      }
   }

   // "ConcreteBuilder2"
   class ConcreteBuilder2 : Builder
   {
      private Product product = new Product();

      public override void BuildPartA()
      {
         product.Add("PartX");
      }

      public override void BuildPartB()
      {
         product.Add("PartY");
      }

      public override Product GetResult()
      {
         return product;
      }
   }

   // "Product"
   class Product
   {
      ArrayList parts = new ArrayList();

      public void Add(string part)
      {
         parts.Add(part);
      }

      public void Show()
      {
         Console.WriteLine("nProduct Parts -------");
         foreach (string part in parts)
            Console.WriteLine(part);
      }
   }
}

Prototype pattern
Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.

UML Diagram

// Prototype pattern -- Structural example
using System;

namespace DoFactory.GangOfFour.Prototype.Structural
{
   // MainApp startup class for Structural
   // Prototype Design Pattern.
   class MainApp
   {
      // Entry point into console application.
      static void Main()
      {
         // Create two instances and clone each
         ConcretePrototype1 p1 = new ConcretePrototype1("I");
         ConcretePrototype1 c1 = (ConcretePrototype1)p1.Clone();
         Console.WriteLine("Cloned: {0}", c1.Id);

         ConcretePrototype2 p2 = new ConcretePrototype2("II");
         ConcretePrototype2 c2 = (ConcretePrototype2)p2.Clone();
         Console.WriteLine("Cloned: {0}", c2.Id);

         // Wait for user
         Console.ReadKey();
      }
   }

   // The 'Prototype' abstract class
   abstract class Prototype
   {
      private string _id;
      // Constructor
      public Prototype(string id)
      {
         this._id = id;
      }
      // Gets id
      public string Id
      {
         get { return _id; }
      }
      public abstract Prototype Clone();
   }

   // A 'ConcretePrototype' class
   class ConcretePrototype1 : Prototype
   {
      // Constructor
      public ConcretePrototype1(string id) : base(id) { }
      // Returns a shallow copy
      public override Prototype Clone()
      {
         return (Prototype)this.MemberwiseClone();
      }
   }

   // A 'ConcretePrototype' class
   class ConcretePrototype2 : Prototype
   {
      // Constructor
      public ConcretePrototype2(string id) : base(id)
      {
      }
      // Returns a shallow copy
      public override Prototype Clone()
      {
         return (Prototype)this.MemberwiseClone();
      }
   }
}

Singleton pattern
Ensure a class has only one instance and provide a global point of access to it.

UML Diagram

// Singleton pattern -- Structural example
using System;

namespace DoFactory.GangOfFour.Singleton.Structural
{
   //
   // MainApp startup class for Structural
   // Singleton Design Pattern.
   //
   class MainApp
   {
      //
      // Entry point into console application.
      //
      static void Main()
      {
         // Constructor is protected -- cannot use new
         Singleton s1 = Singleton.Instance();
         Singleton s2 = Singleton.Instance();

         // Test for same instance
         if (s1 == s2)
         {
            Console.WriteLine("Objects are the same instance");
         }

         // Wait for user
         Console.ReadKey();
      }
   }

   //
   // The 'Singleton' class
   //
   class Singleton
   {
      private static Singleton _instance;

      // Constructor is 'protected'
      protected Singleton()
      {
      }

      public static Singleton Instance()
      {
         // Uses lazy initialization.
         // Note: this is not thread safe.
         if (_instance == null)
         {
            _instance = new Singleton();
         }

         return _instance;
      }
   }
}

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

UML Diagram

using System;

namespace DoFactory.GangOfFour.Decorator.Structural
{
   // MainApp test application

   class MainApp
   {
      static void Main()
      {
         // Create ConcreteComponent and two Decorators
         ConcreteComponent c = new ConcreteComponent();
         ConcreteDecoratorA d1 = new ConcreteDecoratorA();
         ConcreteDecoratorB d2 = new ConcreteDecoratorB();

         // Link decorators
         d1.SetComponent(c);
         d2.SetComponent(d1);

         d2.Operation();

         // Wait for user
         Console.Read();
      }
   }

   // "Component"
   abstract class Component
   {
      public abstract void Operation();
   }

   // "ConcreteComponent"
   class ConcreteComponent : Component
   {
      public override void Operation()
      {
         Console.WriteLine("ConcreteComponent.Operation()");
      }
   }

   // "Decorator"
   abstract class Decorator : Component
   {
      protected Component component;

      public void SetComponent(Component component)
      {
         this.component = component;
      }

      public override void Operation()
      {
         if (component != null)
         {
            component.Operation();
         }
      }
   }

   // "ConcreteDecoratorA"
   class ConcreteDecoratorA : Decorator
   {
      private string addedState;

      public override void Operation()
      {
         base.Operation();
         addedState = "New State";
         Console.WriteLine("ConcreteDecoratorA.Operation()");
      }
   }

   // "ConcreteDecoratorB"
   class ConcreteDecoratorB : Decorator
   {
      public override void Operation()
      {
         base.Operation();
         AddedBehavior();
         Console.WriteLine("ConcreteDecoratorB.Operation()");
      }

      void AddedBehavior()
      {
      }
   }
}

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

UML Diagram

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Composite.Structural
{
    // MainApp test application

    class MainApp
    {
        static void Main()
        {
            // Create a tree structure
            Composite root = new Composite("root");
            root.Add(new Leaf("Leaf A"));
            root.Add(new Leaf("Leaf B"));

            Composite comp = new Composite("Composite X");
            comp.Add(new Leaf("Leaf XA"));
            comp.Add(new Leaf("Leaf XB"));

            root.Add(comp);
            root.Add(new Leaf("Leaf C"));

            // Add and remove a leaf
            Leaf leaf = new Leaf("Leaf D");
            root.Add(leaf);
            root.Remove(leaf);

            // Recursively display tree
            root.Display(1);

            // Wait for user
            Console.Read();
        }
    }

    // "Component"
    abstract class Component
    {
        protected string name;

        // Constructor
        public Component(string name)
        {
            this.name = name;
        }

        public abstract void Add(Component c);
        public abstract void Remove(Component c);
        public abstract void Display(int depth);
    }

    // "Composite"
    class Composite : Component
    {
        private ArrayList children = new ArrayList();

        // Constructor
        public Composite(string name) : base(name)
        {
        }

        public override void Add(Component component)
        {
            children.Add(component);
        }

        public override void Remove(Component component)
        {
            children.Remove(component);
        }

        public override void Display(int depth)
        {
            Console.WriteLine(new String('-', depth) + name);

            // Recursively display child nodes
            foreach (Component component in children)
            {
                component.Display(depth + 2);
            }
        }
    }

    // "Leaf"
    class Leaf : Component
    {
        // Constructor
        public Leaf(string name) : base(name)
        {
        }

        public override void Add(Component c)
        {
            Console.WriteLine("Cannot add to a leaf");
        }

        public override void Remove(Component c)
        {
            Console.WriteLine("Cannot remove from a leaf");
        }

        public override void Display(int depth)
        {
            Console.WriteLine(new String('-', depth) + name);
        }
    }
}

Facade pattern
Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.

UML Diagram

using System;

namespace DoFactory.GangOfFour.Factory.Structural
{
    ///
    /// MainApp startup class for Structural
    /// Factory Method Design Pattern.
    ///
    class MainApp
    {
        ///
        /// Entry point into console application.
        ///
        static void Main()
        {
            // An array of creators
            Creator[] creators = new Creator[2];

            creators[0] = new ConcreteCreatorA();
            creators[1] = new ConcreteCreatorB();

            // Iterate over creators and create products
            foreach (Creator creator in creators)
            {
                Product product = creator.FactoryMethod();
                Console.WriteLine("Created {0}",
                    product.GetType().Name);
            }

            // Wait for user
            Console.ReadKey();
        }
    }

    ///
    /// The 'Product' abstract class
    ///
    abstract class Product
    {
    }

    ///
    /// A 'ConcreteProduct' class
    ///
    class ConcreteProductA : Product
    {
    }

    ///
    /// A 'ConcreteProduct' class
    ///
    class ConcreteProductB : Product
    {
    }

    ///
    /// The 'Creator' abstract class
    ///
    abstract class Creator
    {
        public abstract Product FactoryMethod();
    }

    ///
    /// A 'ConcreteCreator' class
    ///
    class ConcreteCreatorA : Creator
    {
        public override Product FactoryMethod()
        {
            return new ConcreteProductA();
        }
    }

    ///
    /// A 'ConcreteCreator' class
    ///
    class ConcreteCreatorB : Creator
    {
        public override Product FactoryMethod()
        {
            return new ConcreteProductB();
        }
    }
}

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

UML Diagram

using System;

namespace DoFactory.GangOfFour.Strategy.Structural
{
    // MainApp test application
    class MainApp
    {
        static void Main()
        {
            Context context;

            // Three contexts following different strategies
            context = new Context(new ConcreteStrategyA());
            context.ContextInterface();

            context = new Context(new ConcreteStrategyB());
            context.ContextInterface();

            context = new Context(new ConcreteStrategyC());
            context.ContextInterface();

            // Wait for user
            Console.Read();
        }
    }

    // "Strategy"
    abstract class Strategy
    {
        public abstract void AlgorithmInterface();
    }

    // "ConcreteStrategyA"
    class ConcreteStrategyA : Strategy
    {
        public override void AlgorithmInterface()
        {
            Console.WriteLine(
                "Called ConcreteStrategyA.AlgorithmInterface()");
        }
    }

    // "ConcreteStrategyB"
    class ConcreteStrategyB : Strategy
    {
        public override void AlgorithmInterface()
        {
            Console.WriteLine(
                "Called ConcreteStrategyB.AlgorithmInterface()");
        }
    }

    // "ConcreteStrategyC"
    class ConcreteStrategyC : Strategy
    {
        public override void AlgorithmInterface()
        {
            Console.WriteLine(
                "Called ConcreteStrategyC.AlgorithmInterface()");
        }
    }

    // "Context"
    class Context
    {
        Strategy strategy;

        // Constructor
        public Context(Strategy strategy)
        {
            this.strategy = strategy;
        }

        public void ContextInterface()
        {
            strategy.AlgorithmInterface();
        }
    }
}

Chain of responsibility
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 Diagram

using System;

namespace DoFactory.GangOfFour.Chain.Structural
{
    // MainApp test application
    class MainApp
    {
        static void Main()
        {
            // Setup Chain of Responsibility
            Handler h1 = new ConcreteHandler1();
            Handler h2 = new ConcreteHandler2();
            Handler h3 = new ConcreteHandler3();
            h1.SetSuccessor(h2);
            h2.SetSuccessor(h3);

            // Generate and process request
            int[] requests = {2, 5, 14, 22, 18, 3, 27, 20};

            foreach (int request in requests)
            {
                h1.HandleRequest(request);
            }

            // Wait for user
            Console.Read();
        }
    }

    // "Handler"
    abstract class Handler
    {
        protected Handler successor;

        public void SetSuccessor(Handler successor)
        {
            this.successor = successor;
        }

        public abstract void HandleRequest(int request);
    }

    // "ConcreteHandler1"
    class ConcreteHandler1 : Handler
    {
        public override void HandleRequest(int request)
        {
            if (request >= 0 && request < 10)
            {
                Console.WriteLine("{0} handled request {1}",
                    this.GetType().Name, request);
            }
            else if (successor != null)
            {
                successor.HandleRequest(request);
            }
        }
    }

    // "ConcreteHandler2"
    class ConcreteHandler2 : Handler
    {
        public override void HandleRequest(int request)
        {
            if (request >= 10 && request < 20)
            {
                Console.WriteLine("{0} handled request {1}",
                    this.GetType().Name, request);
            }
            else if (successor != null)
            {
                successor.HandleRequest(request);
            }
        }
    }
    
    // "ConcreteHandler3"
    class ConcreteHandler3 : Handler
    {
        public override void HandleRequest(int request)
        {
            if (request >= 20 && request < 30)
            {
                Console.WriteLine("{0} handled request {1}",
                    this.GetType().Name, request);
            }
            else if (successor != null)
            {
                successor.HandleRequest(request);
            }
        }
    }
}

Visitor pattern
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 Diagram

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Visitor.Structural
{
    // MainApp test application
    class MainApp
    {
        static void Main()
        {
            // Setup structure
            ObjectStructure o = new ObjectStructure();
            o.Attach(new ConcreteElementA());
            o.Attach(new ConcreteElementB());

            // Create visitor objects
            ConcreteVisitor1 v1 = new ConcreteVisitor1();
            ConcreteVisitor2 v2 = new ConcreteVisitor2();

            // Structure accepting visitors
            o.Accept(v1);
            o.Accept(v2);

            // Wait for user
            Console.Read();
        }
    }

    // "Visitor"
    abstract class Visitor
    {
        public abstract void VisitConcreteElementA(
            ConcreteElementA concreteElementA);
        public abstract void VisitConcreteElementB(
            ConcreteElementB concreteElementB);
    }

    // "ConcreteVisitor1"
    class ConcreteVisitor1 : Visitor
    {
        public override void VisitConcreteElementA(
            ConcreteElementA concreteElementA)
        {
            Console.WriteLine("{0} visited by {1}",
                concreteElementA.GetType().Name, this.GetType().Name);
        }

        public override void VisitConcreteElementB(
            ConcreteElementB concreteElementB)
        {
            Console.WriteLine("{0} visited by {1}",
                concreteElementB.GetType().Name, this.GetType().Name);
        }
    }

    // "ConcreteVisitor2"
    class ConcreteVisitor2 : Visitor
    {
        public override void VisitConcreteElementA(
            ConcreteElementA concreteElementA)
        {
            Console.WriteLine("{0} visited by {1}",
                concreteElementA.GetType().Name, this.GetType().Name);
        }

        public override void VisitConcreteElementB(
            ConcreteElementB concreteElementB)
        {
            Console.WriteLine("{0} visited by {1}",
                concreteElementB.GetType().Name, this.GetType().Name);
        }
    }

    // "Element"
    abstract class Element
    {
        public abstract void Accept(Visitor visitor);
    }

    // "ConcreteElementA"
    class ConcreteElementA : Element
    {
        public override void Accept(Visitor visitor)
        {
            visitor.VisitConcreteElementA(this);
        }

        public void OperationA()
        {
        }
    }

    // "ConcreteElementB"
    class ConcreteElementB : Element
    {
        public override void Accept(Visitor visitor)
        {
            visitor.VisitConcreteElementB(this);
        }

        public void OperationB()
        {
        }
    }

    // "ObjectStructure"
    class ObjectStructure
    {
        private ArrayList elements = new ArrayList();

        public void Attach(Element element)
        {
            elements.Add(element);
        }

        public void Detach(Element element)
        {
            elements.Remove(element);
        }

        public void Accept(Visitor visitor)
        {
            foreach (Element e in elements)
            {
                e.Accept(visitor);
            }
        }
    }
}
Share

Leave a Reply

Your email address will not be published. Required fields are marked *