Software design patterns are reusable and time-tested solutions for the commonly occurring problems within a given context in software design. It is not a finished design that can be transformed into source or machine code rather it is a template for how to solve problems. Design patterns are originally categorized into 3 sub-classifications:
Creational Patterns:- These provide the capability to create objects based on a required criterion in a controlled way. Some of these patterns are: Factory, Builder, Dependency Injection, Lazy initialization, Multiton, object pool, prototype, resource acquisition is initialization (RAII), Singleton, and so on.
Structural Patterns:- These are about organizing different classes and objects to form larger structures and provide new functionality. Some of these patterns are Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Front controller, Marker, Module, Proxy, Twin, and so on.
Behavioral Patterns:- These are about identifying common communication patterns between objects and realize these patterns. Some of these patterns are Chain of responsibility, command, Interpreter, Iterator, Mediator, Memento, Null Object, Template method, and so on.
There is a big myth in Software Architecture is that for making a good Software Architecture all the design patterns must be implemented in the project. In doing so there is the tendency of forcing design patterns in a project that makes a project complicated and difficult to maintain. Instead of cramping all the patterns that are not necessary for the project, if we implement the design patterns that come out naturally and are completely on-demand as per the scenario, the applications will be more scalable and maintainable. This article aims to show how to use the design patterns in various scenarios of the projects by explaining using C# code.
Before we move further I feel important that we understand the difference between Design Pattern Vs Architecture Pattern Vs Architecture Style? Please go through my article before we proceed here.
Where and how to use the design patterns 1 – Simple Factory?
According to the definition from Wikipedia, Factory Pattern is “A factor is an object for creating other objects”. Simple factory is a class in a simplest form (In comparison to Factory Method Pattern or Abstract Factory Pattern). The Factory class is responsible for instantiating and returning different types of objects upon the conditions passed on to it.
Let’s look at the problem statement that Factory Pattern aims to solve.
We have a customer in our shop. The customer visits the shop and purchases goods and does transaction but we have another type of customer that doesn’t do transaction but only visits the store and we call it Visitor. So for this we prepared the Customerbase (parent) class that is inherited by Customer and Visitor class respectively. Next we created a interface for our Customerbase Class. Now when we need to call different types of customer from our UI the code looks like below:
private void cmdAdd_Click(object sender, EventArgs e)
{
ICustomer iCust = null;
if (cboCustType.SelectedIndex==0)
{
iCust = new Visitor();
}
else
{
iCust = new Customer();
}
iCust.FullName = txtFullName.Text;
iCust.Address = txtAddress.Text;
iCust.PhoneNumber = txtPhoneNo.Text;
iCust.BillDate = dtBillDate.Value;
iCust.BillAmount = Convert.ToDecimal(txtBillAmount.Text);
}
Can you see we have to instantiate the different types of classes in the UI section of our code and thus our US is tightly coupled and is violating the SRP principle. (To know more about tightly coupled, SRP principle you can check out my other article called “Know all the steps of well architected application development“)
So to decouple the code from the UI we can use a simple factory class whose job will be simply creating objects and returning accordingly as per the parameters passed on to it.
using System;
using ICustomerLib;
using CustomerLibrary;
namespace CustomerFactory
{
public class Factory
{
public ICustomer Create(int CustomerType)
{
if (CustomerType==0)
{
return new Visitor();
}
else
{
return new Customer();
}
}
}
}
Now the UI code looks much cleaner by only using the Factory object
private void cmdAdd_Click(object sender, EventArgs e)
{
ICustomer iCust = null;
Factory oFactory = new Factory();
oFactory = new Factory();
iCust = oFactory.Create(cboCustType.SelectedIndex);
iCust.FullName = txtFullName.Text;
iCust.Address = txtAddress.Text;
iCust.PhoneNumber = txtPhoneNo.Text;
iCust.BillDate = dtBillDate.Value;
iCust.BillAmount = Convert.ToDecimal(txtBillAmount.Text);
}
So here we moved object instantitation part to Factory class and Create method in the factory is responsible for creating and returning appropriate objects to UI, so here UI is not worried about making decision or instantiating the objects. This removes the control away from the UI to the Factory class. However we still haven’t fixed the problem now the problem of creating object has shifted from UI to the Factory Class which still violates the SRP principle of the class.
To Fix this we can use the external entity called Unity container that will help perform the dependency injection in the class Factory and will remove control out of the factory class making a fully decoupled architecture. Now if we want to add any more customer type in the system like say “Pensioner”, “Student” etc then we can just inject it via the Unity Config file and we don’t need to change our code.
//// Configuration File to load the Unity Container ////
<configuration>
<configSections>
<section name="unity"
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<container>
<register type="ICustomerLib.ICustomer, ICustomerLib"
mapTo="CustomerLibrary.Visitor, CustomerLibrary" name="0" />
<register type="ICustomerLib.ICustomer, ICustomerLib"
mapTo="CustomerLibrary.Customer, CustomerLibrary" name="1" />
</container>
</unity>
<startup>
<supportedRuntime version="v5.0" sku=".NETFramework,Version=v5.0" />
</startup>
</configuration>
//// Factory Class Code ////
using ICustomerLib;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;
namespace CustomerFactory
{
//Simple Factory Pattern
// To improve perfomance we use singelton pattern so that it
// Can only be instantiated once
public static class Factory
{
static IUnityContainer oUnitCont = null;
static Factory()
{
oUnitCont = new UnityContainer();
// We can directly load the unity container here
//oUnitCont.RegisterType<ICustomer, Visitor> ("0"); //You can get the value from config
//oUnitCont.RegisterType<ICustomer, Customer>("1");
if (ConfigurationManager.GetSection("unity") != null)
{
//Or We can load the entityes to be injected from the configuration file
oUnitCont.LoadConfiguration();
}
}
public static ICustomer Create(int CustomerType)
{
return oUnitCont.Resolve<ICustomer>(CustomerType.ToString());
}
}
}
Where and how to use the design patterns?
2. Strategy Pattern & 3. Dependency Injection
The S of SOLID principle is Single Responsibility Principle that says that a class should only have one responsibility given to it and not overload with too many responsibilities. To achieve SRPc we can have Inversion of Control (IOC) principle to move the responsibility away from the overloaded class. Lets say in our above example we need to validate the customer and the visitor objects which will have separate validations as per the customer type. Now in this case we need to load the validations inside the Customer or Visitor class which is against the SRP principle. Let’s see in the code below:
public class CustomerBase:ICustomer
{
public string FullName { get; set; }
public string PhoneNumber { get; set; }
public decimal BillAmount { get; set; }
public DateTime BillDate { get; set; }
public string Address { get; set; }
public virtual void Validate()
{
// Virtual function created so that it can be override by child class
//let this be defined by child classes.
}
}
Here the base class is asking its child classes to validate their own rules themselves by placing the virtual functions. But now we are assigning responsibility to validate to a class which is overloading the concrete entity class.
Now to solve this problem we can use Strategy Pattern here. Strategy pattern is a behavioral design pattern that enables selecting an algorithm (or a Strategy) at runtime. Strategy lets the logic vary independently from the clients that use it. So to do that lets create separate project that holds all the validation strategies. Here in this project we will add separate validation strategies classes for different types of validation that we need to perform for our entity classes. In our case we need two strategies one for Customer Class and one for Visitor class. In future any more validation strategies we want to add will be in this business layer that consists of various validations for various classes. So to access the validation strategies in a decoupled architecture, we need a generic interface that can call upon the required validation as per the type we pass on to this generic interface. For that we can create a generic type interface called IValidation.
namespace ValidationLogic
{
//Validation logic for customer entity
public class CustomerValidation : IValidation<ICustomer>
{
public void Validate(ICustomer obj)
{
if (obj.FullName.Length == 0)
{
throw new Exception("Customer Full Name is required");
}
if (obj.PhoneNumber.Length == 0)
{
throw new Exception("Customer Phone Number is required");
}
if (obj.BillAmount == 0)
{
throw new Exception("Bill Amount is required");
}
if (obj.BillDate >= DateTime.Now)
{
throw new Exception("Bill Date is not correct");
}
if (obj.Address.Length == 0)
{
throw new Exception("Address is required");
}
}
}
//Validation logic for Visitor Entity
public class VisitorValidation : IValidation<ICustomer>
{
public void Validate(ICustomer obj)
{
if (obj.FullName.Length == 0)
{
throw new Exception("Visitor Full Name is required");
}
if (obj.PhoneNumber.Length == 0)
{
throw new Exception("Visitor Phone Number is required");
}
}
}
}
/// GENERIC
// Validation Interface that has a Validation class and is Generic Interface where we can inject Type
// So when we inject Customer Type it validates the customer and if we inject visitor type it validates the visitor
namespace Interfaces
{
public interface IValidation<InjectType>
{
void Validate(InjectType obj);
}
}
Now we need to use this validation strategies in our customer base class and make our child classes to use the IValidation interface. For that we will create a validation interface object and ask the type of customer that needs to be validated by injecting the customer type object in the constructor.
public class CustomerBase : ICustomer
{
//Create object of Interface validation
private IValidation<ICustomer> _validation = null;
//Inject the Validation strategy in the Customer object
//when the customer object is created it requies what type of validation strategy is required
public CustomerBase(IValidation<ICustomer> objVal)
{
_validation = objVal;
}
// When the Validate method is called we can call the Validation.Validate and pass on the object that is injected in the validation
public virtual void Validate()
{
// Virtual function created so that it can be override by child class
//let this be defined by child classes.
// Clalling the validatoin method and passing the current customer object to be validated
_validation.Validate(this);
}
// Now since we injected a customer type in the base class constructer we need to do the same fo rthe child classes as well
public class Customer : CustomerBase
{
//In the individual child class creating the constructor to call the Validation
//this is injecting Validation strategy here
public Customer(IValidation<ICustomer> objVal):base(objVal)
{
}
}
public class Visitor : CustomerBase
{
//this is injecting Validation strategy here
public Visitor(IValidation<ICustomer> objVal):base(objVal)
{
}
}
}
Now when the Customer object is called the caller has to inject the Validation strategy from outside which is also called the Dependency Injection design pattern. Now we have completely moved the validation strategy from within the class to decide the strategy during the run time by utilizing the Strategy Pattern.
Dependency Injection : Dependency Injection (DI) is a design pattern used to implement IoC (Inversion of Control). It allows the creation of dependent objects outside of a class and provides those objects to a class through different ways. Using DI, we move the creation and binding of the dependent objects outside of the class that depends on them.