The need for factory pattern
In this example below based on the value of the paramater datasource we would need to decide which implementation of IDatasource to use. The problem with a code like this is that it does not adhere to the "closed for modification" design principle. If you add a new implementation of IDataSource called DataFromFile, then you will have to modify the code in the Main() and add a new else statement. Ideally, when you add a new implementation or switch implementation, you shouldn't have to modify code.
To switch from DataFromSQL to DataFromXML, all I should have to do, should be to change a config setting. Factory pattern helps us achieve that.
Simple Factory Pattern
In this pattern we do not need to update the code if we want to switch implementations. All we do is make a change in the config file. These are the key things we need to do to make this happen.
Its called factory pattern because, you pass the name of a class to a factory and it returns an instance of that class for you.
In this example below based on the value of the paramater datasource we would need to decide which implementation of IDatasource to use. The problem with a code like this is that it does not adhere to the "closed for modification" design principle. If you add a new implementation of IDataSource called DataFromFile, then you will have to modify the code in the Main() and add a new else statement. Ideally, when you add a new implementation or switch implementation, you shouldn't have to modify code.
using System;
namespace LearnFactoryPattern
{
class Test
{
static void Main()
{
var datasource = "SQL";
IDataSource iData;
if (datasource.Equals("SQL"))
{
iData = new DataFromSQL();
}
else if
(datasource.Equals("XML"))
{
iData = new DataFromXML();
}
else
{
iData = null;
}
iData.GetData();//Displays Data from SQL
}
}
public interface IDataSource
{
void GetData();
}
public class DataFromSQL : IDataSource
{
public void GetData()
{
Console.WriteLine("Data
from SQL");
}
}
public class DataFromXML : IDataSource
{
public void GetData()
{
Console.WriteLine("Data
from XML");
}
}
}
- Save the name of Implementation of IDatasource we want to use in the config file.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DataSourceImplementationName" value="DataFromSQL" />
</appSettings>
</configuration>
- Load into a Dictionary, all the implementations of IDataSource that we have in the current assembly.
Dictionary<string,
Type> dataSources;
dataSources.Add(typeName,
type);//types in the assembly that implement
IDataSource
- Get the name of implementation from the config file. Pass that class name into a method. That method looks up the dictionary dataSources for a type that matches the class name (type name) we just passed in. Then it creates an instance of that for us.
public IDataSource
CreateInstance(string dataSourceName)
{
......
}
The whole code that implements this is shown below.
using System;
using System.Configuration;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
namespace LearnFactoryPattern
{
class Test
{
static void Main()
{
var dataSourceName = ConfigurationManager.AppSettings["DataSourceImplementationName"].ToLower();
var factory = new DataSourceFactory();
var
dataSource=factory.CreateInstance(dataSourceName);
dataSource.GetData();
}
}
public interface IDataSource
{
void GetData();
}
public class DataFromSQL : IDataSource
{
public void GetData()
{
Console.WriteLine("Data
from SQL");
}
}
public class DataFromXML : IDataSource
{
public void GetData()
{
Console.WriteLine("Data
from XML");
}
}
/*******************************************************/
/**************** FACTORY BELOW ************************/
/*******************************************************/
public class DataSourceFactory
{
Dictionary<string,
Type> dataSources;
public DataSourceFactory()
{
LoadDataSourceTypes();
}
public IDataSource
CreateInstance(string dataSourceName)
{
var dataSourceImplementationName =
GetTypeToCreate(dataSourceName);
return (IDataSource)Activator.CreateInstance(dataSourceImplementationName);
}
public Type
GetTypeToCreate(string dataSourceName)
{
return dataSources[dataSourceName];
}
public void
LoadDataSourceTypes()
{
dataSources = new Dictionary<string,
Type>();
var typesinCurrentAssembly = Assembly.GetExecutingAssembly().GetTypes();//Get the interfaces and classes in the current assembly
var interfaceName = typeof(IDataSource).ToString();//"IDataSource"
foreach (var type in typesinCurrentAssembly)
{
if (type.GetInterface(interfaceName) != null)//Find the types that
implement IDataSource
{
var typeName = type.Name.ToLower();
dataSources.Add(typeName, type);
}
}
}
}
}
Its called factory pattern because, you pass the name of a class to a factory and it returns an instance of that class for you.
No comments:
Post a Comment
Comments will appear once they have been approved by the moderator