Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Factory Pattern without a Switch or If/Then

Tags:

I'm looking for a simple example of how to implement a factory class, but without the use of a Switch or an If-Then statement. All the examples I can find use one. For example, how could one modify this simple example (below) so that the actual factory does not depend on the Switch? It seems to me that this example violates the Open/Close principle. I'd like to be able to add concrete classes ('Manager', 'Clerk', 'Programmer', etc) without having to modify the factory class.

Thanks!

class Program {     abstract class Position     {         public abstract string Title { get; }     }      class Manager : Position     {         public override string Title         {             get  { return "Manager"; }         }     }      class Clerk : Position     {         public override string Title         {             get { return "Clerk"; }         }     }      class Programmer : Position     {         public override string Title         {             get { return "Programmer"; }         }     }      static class Factory     {         public static Position Get(int id)         {             switch (id)             {                 case 0: return new Manager();                 case 1: return new Clerk();                 case 2: return new Programmer();                 default: return new Programmer();             }         }     }      static void Main(string[] args)     {         for (int i = 0; i <= 2; i++)         {             var position = Factory.Get(i);             Console.WriteLine("Where id = {0}, position = {1} ", i, position.Title);         }         Console.ReadLine();     } } 

UPDATE:

Wow! Thanks everyone! I have learned a ton. After revewing all the feedback, I blended a few of the answers and came up with this. I'd be open to further dialog about a better way to do this.

class Program {      public interface IPosition     {         string Title { get; }     }      class Manager : IPosition     {         public string Title         {             get { return "Manager"; }         }     }      class Clerk : IPosition     {         public string Title         {             get { return "Clerk"; }         }     }      class Programmer : IPosition     {         public string Title         {             get { return "Programmer"; }         }     }  static class PositionFactory {     public static T Create<T>() where T : IPosition, new()     {         return new T();     } }   static void Main(string[] args)     {          IPosition position0 = PositionFactory.Create<Manager>();         Console.WriteLine("0: " + position0.Title);          IPosition position1 = PositionFactory.Create<Clerk>();         Console.WriteLine("1: " + position1.Title);          IPosition position2 = PositionFactory.Create<Programmer>();         Console.WriteLine("1: " + position2.Title);          Console.ReadLine();     } } 

Another Edit:

It's also possible to create an instance of the Interface using an unknown type:

static class PositionFactory {    public static IPosition Create(string positionName)     {                Type type = Type.GetType(positionName);         return (IPosition)Activator.CreateInstance(type);     } } 

Which could then be called as follows:

IPosition position = PositionFactory.Create("Manager"); Console.WriteLine(position.Title); 
like image 376
Casey Crookston Avatar asked Nov 23 '15 18:11

Casey Crookston


People also ask

How do you remove if else condition in factory pattern?

Object Oriented Language has very powerful feature of Polymorphism, it is used to remove if/else or switch case in code. Code without condition is easy to read. There are some places where you have to put them and one of such example is Factory/ServiceProvider class.

Does factory pattern need interface?

Factory Method lets a class defer instantiation to subclasses. So an Interface seems to be an important part of the Factory Design Pattern, but the only reason I found where its practical is when you make a collection in the main method.

What simple factory pattern can do?

This allows interfaces for creating objects without exposing the object creation logic to the client. Factory Method Pattern. This allows interfaces for creating objects, but allow subclasses to determine which class to instantiate.

What is the difference between factory pattern and facade pattern?

The facade pattern is used when you want to hide an implementation or it is about changing interface of some class or set of classes. Builder hides the process of construction by decomposing it in smaller steps. Abstract factory pattern is used when you want to hide the details on constructing instances.


1 Answers

How about this (no Dictionary required and note that you will get an syntax error if your try to Create<Position>()):

EDIT - Updated to use an IPosition interface implemented explicitly. Only instances of IPosition can access the member functions (e.g. <implementation of Manager>.Title will not compile).

EDIT #2 Factory.Create should return an IPosition not T when using the interface properly.

using System; using System.Collections.Generic;  class Program {     interface IPosition     {         string Title { get; }         bool RequestVacation();     }      class Manager : IPosition     {          string IPosition.Title         {             get { return "Manager"; }         }          bool IPosition.RequestVacation()         {             return true;         }     }      class Clerk : IPosition     {         int m_VacationDaysRemaining = 1;          string IPosition.Title         {             get { return "Clerk"; }         }          bool IPosition.RequestVacation()         {             if (m_VacationDaysRemaining <= 0)             {                 return false;             }             else             {                 m_VacationDaysRemaining--;                 return true;             }         }     }      class Programmer : IPosition     {         string IPosition.Title         {             get { return "Programmer"; }         }          bool IPosition.RequestVacation()         {             return false;         }     }      static class Factory     {         public static IPosition Create<T>() where T : IPosition, new ()         {             return new T();         }     }      static void Main(string[] args)     {         List<IPosition> positions = new List<IPosition>(3);         positions.Add(Factory.Create<Manager>());         positions.Add(Factory.Create<Clerk>());         positions.Add(Factory.Create<Programmer>());          foreach (IPosition p in positions) { Console.WriteLine(p.Title);  }         Console.WriteLine();          Random rnd = new Random(0);         for (int i = 0; i < 10; i++)         {             int index = rnd.Next(3);             Console.WriteLine("Title: {0}, Request Granted: {1}", positions[index].Title, positions[index].RequestVacation());         }          Console.ReadLine();     } } 
like image 177
Clay Ver Valen Avatar answered Sep 21 '22 22:09

Clay Ver Valen