Design Patterns

C# - Design-guidelines  - This link is providing guidelines to design frameworks.


Introduction to Design Patterns


1. Singleton

Some classes should have only one instance.

Examples: 1. Access to a compute file system
2. Access to window task manager
3. Access to a Network's Printer Spooler

Commonly, Singletons should be created when they are first needed. (Lazy construction)

Intent - 

Ensure a Class has only one Instance.
Making the class itself responsible to keeping track of its sole Instance.
"There can be only One"

Applicability - 

Use Singleton pattern when:

1. There must be one and only one instance of class.
2. The Class Must be accessible to clients.
3. Class should not require parameters as part of it's Construction

when creating the Instance is expensive, a Singleton can improve Performance.

Example -

 class Program
    {
        static void Main(string[] args)
        {
            // Usage of Singleton
            Singleton.Instance.Todo();
            // other way assign singleton to variable then use
            var single = Singleton.Instance;
            single.Todo();
            // other way pass as paramtere -- static class we can not pass a parameter
            Doing(Singleton.Instance);
        }

        static void Doing(Singleton s)
        {
            s.Todo();
        }
    }
    class Singleton
    {
        private static Singleton instance;
        private Singleton()
        {

        }
        public static Singleton Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
                return instance;
            }
        }

        public void Todo()
        {

        }
    }
But it's not thread safe. Lets create Thread Safe and Fast Singleton code

public class LazySingleton
    {
        private LazySingleton() { }
        public static LazySingleton Instance
        {
            get
            {
                return Nested.instance;
            }
        }
        private class Nested
        {
            static Nested() { }
            internal static readonly LazySingleton instance = new LazySingleton();
        }

    }

In above thread safe example Static Nested() constructor is there becauseWhen all static data is initialized inline and an explicit static constructor is not declared, Microsoft intermediate language (MSIL) compilers add the beforefieldinit flag and an implicit static constructor, which initializes the static data, to the MSIL type definition.


Consequences
1. Singleton introduce tight coupling among collaborating classes.
2. Singletons are not or seriously difficulty to TEST.
3. Using an IOC container - it is straight forward to avoid coupling and testability issues.

Single Responsibility - 
Management of object life time is a single responsibility, 
we add this responsibility to a singleton class which is responsible for other responsibilities then it's violating SRP(Single Responsibility Principle). 
using an IOC Container, a separate class can be responsible for managing lifetime objects.

Singleton Design Pattern      Beforefieldinit

Other Related Patterns: Factory Method, Builder, Abstract Factory


2. Repository

Intent - Encapsulate data Access Logic -
Data appears to live an in memory collection.
Visit below MSDN link to study in detail.
The Repository Pattern MSDN

Consequences -
More classes and less duplicate codes.
Maintainability, Flexibility, Testability

Related Patterns - 
Unit Of Work - All operation should follow ACID rules.
Specification -you want to implement additional query methods in repository/
Identity Map - responsible to manage identities like row identity
Decorator - responsible for other things like you want to implement a cache repository between business layer and original repository.

3. Specification Pattern

This pattern is about encapsulating domain rules into specification classes. These are then used to test if a particular domain object satisfies the criteria. Typically, they expose a public function called IsSatisifiedBy() that returns a boolean based on whether the object satisfies the specification.
For example, if we have a bank account value object…
public class BankAccount
{
   public int CurrentBalance( get; set;}
}
..we may define a specification to test whether the bank is overdrawn…
public interface ISpecification
{
  bool IsSatisfiedBy(BankAccount account);
}

public class AccountOverdrawnSpecification: ISpecification
{
  public bool IsSatisfiedBy(BankAccount account)
  {
     return (account.CurrentBalance < 0);
  }
}
..which can then be used in our code.
ISpecification overdrawnSpecification = 
  new AccountOverdrawnSpecification();

var account = new BankAccount(){ CurrentBalance = -10};
if (overdrawnSpecification.IsSatisfiedBy(account))
{
  throw new AccountOverdrawnException();
}
The main advantage of this pattern is that any logical decisions within the code will be based upon language the customer would understand. It also makes the code more readable, which will benefit other developers when they need to understand the system.
An additional feature of this pattern is that the specifications can be ‘chained’ using boolean logic to create more complex specifications. Below is an example of this in action:
ISpecification complexSpecification = 
  new AccountOverdrawnSpecification().And(
    new AccountEmptySpecification().Or(new AccountValueSpecification()));

var account = new BankAccount(){ CurrentBalance = -10};
if (complesSpecification.IsSatisfiedBy(account))
{
  throw new AccountException();
}
So, how do we implement this in .NET? Fortunately, generics and extension methods allow us to provide a set of classes that are flexible enough to meet the requirements of this pattern under most circumstances.
First of all, we should amend the ISpecification interface to be type safe by making it a generic interface:
public interface ISpecification<TEntity>
{
  bool IsSatisfiedBy(TEntity entity);
}
Then we need to define the helper classes that allow us to perform the boolean comparisons (AND, OR and NOT). Below is the code for the AndSpecification class:
internal class AndSpecification<TEntity> : ISpecification<TEntity>
{
  private ISpecification<TEntity> _specificationOne;
  private ISpecification<TEntity> _specificationTwo;

  internal AndSpecification(ISpecification<TEntity> specificationOne, 
    ISpecification<TEntity> specificationTwo)
  {
    this._specificationOne = specificationOne;
    this._specificationTwo = specificationTwo;
  }

  public bool IsSatisfiedBy(TEntity entity)
  {
    return (this._specificationOne.IsSatisfiedBy(entity) && 
      this._specificationTwo.IsSatisfiedBy(entity));
   }
}  
Finally we need to enable the chaining functionality on objects that implement ISpecification by writing extension methods for And(), Or() and Not(), like this:
public static class SpecificationExtensionMethods
{        
  public static ISpecification<TEntity> And<TEntity>(
    this ISpecification<TEntity> specificationOne,
    ISpecification<TEntity> specificationTwo)
  {
    return new AndSpecification<TEntity>(
      specificationOne, specificationTwo);
  }

  public static ISpecification<TEntity> Or<TEntity>(
    this ISpecification<TEntity> specificationOne,
    ISpecification<TEntity> specificationTwo)
  {
     return new OrSpecification<TEntity>(
       specificationOne, specificationTwo);
  }

  public static ISpecification<TEntity> Not<TEntity>(
    this ISpecification<TEntity> specification)
  {
    return new NotSpecification<TEntity>(specification);
  }
}
Now, any specifications we want to define must inherit from the new generic interface. Here is a refactor of the AccountOverdrawnSpecification:
public class AccountOverdrawnSpecification: ISpecification<BankAccount>
{
  public bool IsSatisfiedBy(BankAccount entity)
  {
     return (entity.CurrentBalance < 0);
  }
} 
That is all we need to do in order to implement this pattern in a reusable manor in .NET.

3. Unit of Work -

Why - Easy Data Access.
- Manage Concurrency Problems.
- Manage Transactions.

In UOW business layer does not need to worry about like what objects has changed because UOW will take care for all. for example - Customers and Order two are related entities then UOW commit operation will save both entities in atomic way.

Applicability - Any time you need data persistence.
 - Commonly implemented by persistence frameworks.
        (ORMs - N-Hibernate - concepts of sessions implement Unit of Work Pattern, Entity framework)
        ADO.NET (Data Sets and Adapter)

Related Patterns - Repository Pattern , Identity Pattern - To manage the identity of a row in data base

Summary - 

Keep business logic free of data access code.
keep free business logic from tracking changes.
allow business logic to work with logical transactions.



5. Factory Patterns - 

Consider Factories when - 

1. Unsure which  concrete implementation of interface i want to return.
2. Creation of object should be separated from representation of an Object.
3. Lots of If/Else or Switch blocks when deciding which concrete class need to create so better to refactor the code using factory pattern.

General example - 

Intention - separate object creation from the decisions of which  object to create.
 - Adding new classes and features without breaking OCP. - 
        Factory produced objects, Factories them selves.
- Store which Object to create outside of program.

Simple Factory  Pattern - 
- Encapsulate object creation.
- Allows for late bound decisions regarding instantiation
 -- configured based
 -- input or other dunamic data
 --  other persistance storage
- Caller class knows what concrete factory it needs.


namespace DesignPatterns
{
    public class WithoutFactoryPattern
    {
        public static IAuto GetCar(string carName)
        {
            switch (carName)
            {
                case "BMW":
                    return new BMW();
                case "Harrier":
                    return new Harrier();
                default:
                    return null;
            }
        }
    }

    public interface IAuto
    {
        void TurnOn();

        void TurnOff();
    }

    class BMW : IAuto
    {
        public void TurnOff()
        {
            Console.WriteLine("Turning off BMW");
        }

        public void TurnOn()
        {
            Console.WriteLine("Turning on BMW");
        }
    }

    class Harrier : IAuto
    {
        public void TurnOff()
        {
            Console.WriteLine("Turning off Harrier");
        }

        public void TurnOn()
        {
            Console.WriteLine("Turning on Harrier");
        }
    }

    public class FactoryPattern
    {
        Dictionary<string, Type> autos;
        public FactoryPattern()
        {
            LoadTypeICanReturn();
        }

        public IAuto CreateInstance(string name)
        {
            Type t = GetTypeToCreate(name);
            if (t == null)
            {
                return null; // here we can use null pattern
            }
            return Activator.CreateInstance(t) as IAuto;
        }

        Type GetTypeToCreate(string carName)
        {
            foreach (var auto in autos)
            {
                if (auto.Key.Contains(carName))
                {
                    return autos[auto.Key];
                }
            }
            return null;
        }
        void LoadTypeICanReturn()
        {
            autos = new Dictionary<string, Type>();
            Type[] typesInThisAssembly = Assembly.GetExecutingAssembly().GetTypes();
            foreach (Type t in typesInThisAssembly)
            {
                if (t.GetInterface(typeof(IAuto).Name.ToString()) != null)
                {
                    autos.Add(t.Name.ToLower(), t);
                }
            }
        }
    }
}

Calling Client Code:
static void TestFactory()
        {
            // without Factory Pattern
            var car = WithoutFactoryPattern.GetCar("Harrier");
            if (car != null)
            {
                car.TurnOn();
                car.TurnOff();
            }
            else
            {
                Console.WriteLine("No matching car found");
            }

            // its using factory pattern
            // here we or calling class know about concrete factory it's going to create
            FactoryPattern factory = new FactoryPattern();
            var bmw = factory.CreateInstance("bmw");
            bmw.TurnOn();
            bmw.TurnOff();
        }


Factory Method Pattern - defines an interface for creating an object, but let the sub class decide which class to instantiate. Factory methods lets a class defer instantiation to sub classes.
- Its add an interface to factory it self from Simple factory
- defers object creation to multiple factories that share an interface.
- derived class override or implement factory method of base class.


No comments:

Post a Comment