Generic Factory Pattern, Open/Closed
The Factory Pattern is a common software development code pattern for creating objects. In this Factory Pattern example we will create a Generic Factory that conforms to the open/closed principle.
- open/closed principle
- Software classes, modules, functions etc. should be open for extension, but closed for modification
So in this example we will create a Factory that can be extended without having to edit the Factory class.
The quasi-real world example used here is based on returning Workflow Controllers for managing content of different types within a Content Management System.
First lets create the Interface that the objects the Factory returns will all conform to:
namespace AdvancedGenericFactoryPatternTestApp { public interface IWorkflowController { void Approve(); void Update(); void Reject(); void Archive(); } }
Now lets create the two example Workflow Controllers.
News content WorkflowController.
namespace AdvancedGenericFactoryPatternTestApp.Controllers { public class NewsWorkflowController : IWorkflowController { private readonly bool _enableAuditing; public NewsWorkflowController() { Console.WriteLine("Auditing: " + _enableAuditing); } public NewsWorkflowController(bool enableAuditing) { _enableAuditing = enableAuditing; Console.WriteLine("Auditing: " + _enableAuditing); } public void Approve() { //logic here Console.WriteLine("NewsWorkflowController.Approve"); } public void Update() { //logic here Console.WriteLine("NewsWorkflowController.Update"); } public void Reject() { //logic here Console.WriteLine("NewsWorkflowController.Reject"); } public void Archive() { //logic here Console.WriteLine("NewsWorkflowController.Archive"); } } }
Events content WorkflowController.
namespace AdvancedGenericFactoryPatternTestApp.Controllers { public class EventsWorkflowController : IWorkflowController { private readonly bool _enableAuditing; public EventsWorkflowController() { Console.WriteLine("Auditing: " + _enableAuditing); } public EventsWorkflowController(bool enableAuditing) { _enableAuditing = enableAuditing; Console.WriteLine("Auditing: " + _enableAuditing); } public void Approve() { //logic here Console.WriteLine("EventsWorkflowController.Approve"); } public void Update() { //logic here Console.WriteLine("EventsWorkflowController.Update"); } public void Reject() { //logic here Console.WriteLine("EventsWorkflowController.Reject"); } public void Archive() { //logic here Console.WriteLine("EventsWorkflowController.Archive"); } } }
Notice that the Workflow Controllers has two Constructors, one of which takes a Boolean value.
OK, now we are ready to create our Generic Workflow Controller Factory
namespace AdvancedGenericFactoryPatternTestApp { public class Factory< T > { private readonly Dictionary< string, Type > _factoryDictionary = new Dictionary< string, Type >(); public Factory() { Console.WriteLine("Factory Constructor"); Type[] types = Assembly.GetAssembly(typeof (T)).GetTypes(); foreach (Type type in types) { if (!typeof (T).IsAssignableFrom(type) || type == typeof (T)) { // Incorrect type continue; } Console.WriteLine(string.Format("Factory adding: {0}", type.Name)); // Add the type _factoryDictionary.Add(type.Name, type); } } public T Create< V >(params object[] args) { return (T) Activator.CreateInstance(_factoryDictionary[typeof (V).Name], args); } } }
The Constructor uses Reflection on current assembly to find all the types based on Type T and then stores them into a Dictionary. Type T in our case is the Interface.
The Create method takes a Type V and an array of arguments of type Object, and returns an Object of Type T. Which will be the Interface.
Next lets use the Generic Factory to manage some content.
namespace AdvancedGenericFactoryPatternTestApp { internal class Program { private static IWorkflowController _controller; private static void Main(string[] args) { Factory< IWorkflowController > factory = new Factory< IWorkflowController >(); object[] controllerArguments = {true}; _controller = factory.Create< EventsWorkflowController >(controllerArguments); _controller.Approve(); _controller.Update(); _controller.Reject(); _controller.Archive(); _controller = factory.Create< NewsWorkflowController >(); _controller.Approve(); _controller.Update(); _controller.Reject(); _controller.Archive(); Console.ReadKey(); } } }
Notice that in the case of the Events Workflow Controller we pass in an Object Array with a Boolean value of true.
This is the output
Factory Constructor Factory adding: NewsWorkflowController Factory adding: EventsWorkflowController Auditing: True EventsWorkflowController.Approve EventsWorkflowController.Update EventsWorkflowController.Reject EventsWorkflowController.Archive Auditing: False NewsWorkflowController.Approve NewsWorkflowController.Update NewsWorkflowController.Reject NewsWorkflowController.Archive
You can see from the output that the Object Array value was passed to the correct Constructor.
You can download the Advanced Generic Factory Pattern here
Add Yours
YOU