C# Design Patterns - ablealias/MVC GitHub Wiki

A Design Pattern is a general reusable solution to commonly occurring software problems. Design Patterns are just a blueprint for a solution, it is not a finished specification that can be transformed directly into code.

Design Pattern benefits are

  • Produce high-level solutions for a software problem
  • Ignore the code implementation details
  • Write understandable, testable, and maintainable solutions

Maintainability is one of the most important benefits

Creational

This type deals with object creation and initialization. This pattern gives the program more flexibility including which objects need to be created for a given case.

Factory Method Pattern

Define an interface for creating an object, but let subclasses decide which class to instantiate. This lets a class defer instantiation to subclasses. So, what is that means? Allow programmers to request objects and have the correct type created behind the scene and returned. Factory Method design pattern defines a separate operation (factory method) for creating an object. In other words, create an object by calling a factory method. Factory Method pattern basically work as shown below,

Let's see some sample code, this code would show how to implement a factory method pattern. This demo code returns credit card account balance for two different credit union objects depends on the credit card number we passed. So, I have two credit union objects, for example, Citi Bank and National Bank objects. So, we need a factory method to create an object depends on the credit card number we passed.

The first thing, we need to create a contract (an abstract class) for Credit Accounts, so go ahead and create,

// the Product interface in the above UML diagram
public abstract class ICreditAccount
{
    public decimal Balance { get; set; }
}

Following that, we need to create the Concrete classes for the Citi Bank and National Bank that implements the ICreditAccount contract, so go ahead and create,

// the ConcreteProduct in the above UML diagram
public class CitiCreditAccnt : ICreditAccount
{
   public CitiCreditAccnt()
   {
       Balance = 5000;
   }
}

public class NationalCreditAccnt : ICreditAccount
{
   public NationalCreditAccnt()
   {
       Balance =2000;
   }
}

Next, we need to create the creator factory interface, called ICreditUnionFactory have a method signature which returns a type of ICreditAccount for an operation called GetCreditAccount, let's go and create,

// Factory creator in the UML diagram
interface ICreditUnionFactory
{
    ICreditAccount GetCreditAccount(string accntNo);
}

Next, we need to create the Concrete creator factory class, which is called CreditAccntFactory and it implements ICreditUnionFactory. and this is a significant part of the factory method because it contains the logic that determines what type is going to be sent back. Let's go and create,

// ConcreteFactory in the UML diagram
public class CreditAccntFactory : ICreditUnionFactory
{
    public ICreditAccount GetCreditAccount(string accntNo)
    {
        if(accntNo.Contains("CITI"))
        {
            return new CitiCreditAccnt();
        }
        else if(accntNo.Contains("NATIONAL")
        {
            return new NationalCreditAccnt();
        }
        else
           throw new ArgumentException("Invalid Credit Card");
    }
}

Next to the final thing, how the client instantiates the objects, let's see,

var factory = new CreditAccntFactory as ICreditUnionFactory;
var citiCredit = factory.GetCreditAccount("CITI-1235-567");
var nationalCredit = factory.GetCreditAccount("NATIONAL-1235-567");
Console.WriteLine($"Citi Credit Balance is ${citiCredit.Balance} \n National Credit Balance is ${nationalCredit.Balance}";

Abstract Factory Pattern

Providing an interface for creating families of related or dependent objects without specifying their concrete classes. That means, it's like the factory method pattern, but everything is encapsulated, it's a higher level of abstraction. Ultimately a factory for other factories.

Let's look at the UML diagram for the Abstract Factory pattern

Now let's see a demo, in this demo I have two types of object 1. LoanAccount 2. SavingsAccount, let's do the code.

// AbstractProductA & AbstractProductB in the UML diagram
public interface ILoanAccount 
{
}
public interface ISavingsAccount
{ 
}

Now we have declared the interfaces for LoanAccount and SavingsAccount type. Now we need to define an Abstract Factory class with the operations that return the abstract types. Let's do the code,

// AbstractFactory in the UML diagram
public abstract class ICreditUnionFactory
{
    public abstract ILoanAccount CreateLoanAccount();
    public abstract ISavingsAccount CreateSavingsAccount();
}

Next, we need to create the Concrete classes for Loan Account and Savings Account that implements the _ILoanAccount _and ISavingsAccount. so, let's create the code,

// ProductA1 in the UML diagram
public class CitiLoanAccount : ILoanAccount
{
    public CitiLoanAccount()
    {
        Console.WriteLine("Return from Citi Loan Account");
    }
}

// ProductA2 in the UML diagram
public class CitiSavingsAccount : ISavingsAccount
{
    public CitiSavingsAccount ()
    {
        Console.WriteLine("Return from Citi Savings Account");
    }
}

// ProductB1 in the UML diagram
public class NationalLoanAccount : ILoanAccount
{
    public NationalLoanAccount()
    {
        Console.WriteLine("Return from National Loan Account");
    }
}

// ProductB2 in the UML diagram
public class NationalSavingsAccount : ISavingsAccount
{
    public NationalSavingsAccount ()
    {
        Console.WriteLine("Return from National Savings Account");
    }
}

Now, the big thing is to create the Concrete classes for Abstract Factory class, so let's do that,

// ConcreteFactory1 in UML diagram
public class CitiCreditUnionFactory : ICreditUnionFactory
{
	public override ILoanAccount CreateLoanAccount()
	{
		CitiLoanAccount obj = new CitiLoanAccount();
		return obj;
	}

	public override ISavingsAccount CreateSavingsAccount()
	{
		CitiSavingsAccount obj = new CitiSavingsAccount();
		return obj;
	}
}
// ConcreteFactory2 in UML diagram
public class NationalCreditUnionFactory : ICreditUnionFactory
{
	public override ILoanAccount CreateLoanAccount()
	{
		CitiLoanAccount obj = new CitiLoanAccount();
		return obj;
	}

	public override ISavingsAccount CreateSavingsAccount()
	{
		CitiSavingsAccount obj = new CitiSavingsAccount();
		return obj;
	}
}

Now, we need to implement a provider static class called CreditUnionFactoryProvider which will return ICreditUnionFactory type depends on the client passing account number. So, create the provider class,

public class CreditUnionFactoryProvider
{
	public static ICreditUnionFactory GetCreditUnionFactory(string accntNo)
	{
		if (accntNo.Contains("CITY"))
		{
		    return new CitiCreditUnionFactory();
		}
		else if (accntNo.Contains("NATIONAL"))
		{
		    return new NationalCreditUnionFactory();
		}
		else
		   return null;
	}
  
}

Finally, we have to instantiate the object in the client depends on the user input, let's do that next,

static void Main(string[] args)
{
	ICreditUnionFactory abstractFactory = CreditUnionFactoryProvider.GetCreditUnionFactory("NATIONAL-12345 567");
	ILoanAccount Loan =  abstractFactory.CreateLoanAccount();
	Console.ReadLine();
}

Difference between Abstract Factory and Factory Method design patterns are as follows:

  • Factory Method is used to create only one product but Abstract Factory is about creating families of related or dependent products.
  • Factory Method pattern exposes a method to the client for creating the object whereas in case of Abstract Factory they expose a family of related objects which may consist of these Factory methods.
  • Factory Method pattern hides the construction of single object whereas Abstract factory method hides the construction of a family of related objects. Abstract factories are usually implemented using (a set of) factory methods.
  • Abstract Factory pattern uses composition to delegate the responsibility of creating an object to another class while the Factory Method pattern uses inheritance and relies on the derived class or subclass to create an object.
  • The idea behind the Factory Method pattern is that it allows for the case where a client doesn't know what concrete classes it will be required to create at runtime, but just wants to get a class that will do the job, while Abstract Factory pattern is best utilised when your system has to create multiple families of products or you want to provide a library of products without exposing the implementation details.

Structural

This type deals with Class and Object composition. This pattern focuses on decoupling interface and implementation of classes and its objects.

Behavioural

This type deals with communication between classes and objects, that is how objects communicate with each other.