0

I came across a term called reflection. It is a feature commonly used in factory design patterns. I had a hard time understanding the concept because I’m still learning how to program. How can reflection be used in factory design patterns in C# or Java? Can anyone give me a simple example, and show me your code that uses reflection to implement factory design patterns?

Microsoft provides this code example of reflection, but i don't see how this can be used in factory design patterns.

 // Using GetType to obtain type information: 
  int i = 42;
  System.Type type = i.GetType();
  System.Console.WriteLine(type);

  The Output is: System.Int32
  • 2
    It's not 'commonly used' with Factories and I doubt you'll need reflection until quite a while. And most of the time the need to use reflection comes from a poorly designed architecture. It has its use cases, but a beginner should not need it. – Pierre-Luc Pineault Aug 02 '15 at 04:45
  • @Pierre-LucPineault Thanks for clearing that up. Can you give me a simple code example of when i would need to use it. I want to understand it. –  Aug 02 '15 at 04:50
  • It's not code, but here's [some general examples of use cases](http://stackoverflow.com/questions/49737/use-cases-for-reflection) and one [with factory pattern](http://stackoverflow.com/a/429982/2316200). There's a ton of code examples on the web. – Pierre-Luc Pineault Aug 02 '15 at 04:53
  • 2
    Reflection can be used in many scenarios. It does not mean poorly designed architecture. Example: ASP.NET MVC purely uses reflection to create types, use declarative extensions (ActionFilters are examples) and other attribute goodness. Also, automated unit testing frameworks internally use reflection to identify and run unit test cases. Factories however, do not require(although, you could use reflection to create objects) and certain object factories which rely on reflection include those in IoC/DI containers and such. software. – Aniket Inge Aug 02 '15 at 05:01
  • But surely, you do not need to know deeply about reflection unless you are constructing complex – Aniket Inge Aug 02 '15 at 05:02
  • @Aniket I'm getting a little confused here, reflection sounds like a complex feature to understand for me. If you can, can you show me a simple code example that uses reflection to implement factory design patterns. –  Aug 02 '15 at 05:08
  • 1
    @LearningToCode You made the original claim that reflection is "commonly used in factory design patterns", so maybe you have an example instead? Where did you hear this? – 31eee384 Aug 02 '15 at 05:15
  • @31eee384 i read this in a text book and The text book said Reflection is used in design patterns like "factory design patterns." Also http://www.slideshare.net/sgganesh/understanding-and-using-reflection talks about it. Use Control F to find factory design patterns section in the site. –  Aug 02 '15 at 05:22
  • @LearningToCode equivalent of reflection (like typeof and enumeration of properties) is used in JavaScript all the time and no one calls it "complex"... – Alexei Levenkov Aug 02 '15 at 05:41

2 Answers2

6

I would never use reflection to implement Factory design pattern, unless there was a special case. The below code is a terrible way to implement the factory design pattern. But since you wanted to know "How" to use reflection for factory design pattern here's the example:

namespace NaiveFactory
{

    public interface Shape
    {
        void Draw();
    }

    public class Circle : Shape
    {
        public void Draw() { Console.WriteLine("Drawing Circle"); }
    }

    public class Rectangle : Shape
    {
        public void Draw() { Console.WriteLine("Drawing Rectangle"); }
    }

    public class ShapeFactory
    {
        public static Shape GetShape<T>() where T : Shape
        {
            return Activator.CreateInstance<T>();
        }

        public static Shape GetShape(string shapeName)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var type = assembly.GetType(shapeName).FullName;
            return (Shape) Activator.CreateInstanceFrom(assembly.Location, type).Unwrap();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var shape = ShapeFactory.GetShape<Circle>();
            var shape2 = ShapeFactory.GetShape("NaiveFactory.Rectangle");
            shape.Draw();
            shape2.Draw();
            Console.ReadKey();
        }
    }
}

EDIT As per suggestion from @AlexeiLevenkov, I have added something close to Dependency injection and instantiating the Shape objects using Constructor Injection as well as with a method:

namespace NaiveFactory
{
    public interface IBoard
    {
        void InternalDraw(string str);
    }

    public class ConsoleBoard : IBoard
    {
        public void InternalDraw(string str) { Console.WriteLine(str); }
    }

    public class DebugBoard : IBoard
    {
        public void InternalDraw(string str) { Debug.WriteLine(str); }
    }

    public interface Shape
    {
        IBoard Board { get; set; }
        void Draw();
        void SetBoard(IBoard board);
    }

    public class Circle : Shape
    {
        public IBoard Board { get; set; }

        public Circle()
        {

        }

        public Circle(IBoard board)
        {
            Board = board;
        }

        public void Draw() { Board.InternalDraw("Drawing Circle"); }

        public void SetBoard(IBoard board)
        {
            Board = board;
        }
    }

    public class Rectangle : Shape
    {
        public IBoard Board { get; set; }

        public Rectangle()
        {

        }

        public Rectangle(IBoard board)
        {
            Board = board;
        }

        public void Draw() { Board.InternalDraw("Drawing Rectangle"); }

        public void SetBoard(IBoard board)
        {
            Board = board;
        }
    }

    public class ShapeFactory
    {
        private static Dictionary<Type, Type> _configurationData = new Dictionary<Type, Type>();

        public static Shape GetShape<T>() where T : Shape
        {
            return Activator.CreateInstance<T>();
        }

        public static void ConfigureContainer<T, U>()
        {
            _configurationData.Add(typeof(T), typeof(U));
        }

        public static Shape GetShape_UsingConstructorInjection(string shapeName)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var type = assembly.GetType(shapeName);
            var constructor = type.GetConstructor(_configurationData.Keys.ToArray());
            if (constructor != null)
            {
                var parameters = constructor.GetParameters();
                return (from parameter in parameters where _configurationData.Keys.Contains(parameter.ParameterType) 
                        select Activator.CreateInstance(_configurationData[parameter.ParameterType]) into boardObj 
                        select (Shape) Activator.CreateInstance(type, boardObj)).FirstOrDefault();
            }
            return null;
        }

        public static Shape GetShape_UsingSetBoardMethod(string shapeName)
        {
            var assembly = Assembly.GetExecutingAssembly();
            var type = assembly.GetType(shapeName);
            var shapeObj = (Shape) Activator.CreateInstance(type);
            if (shapeObj != null)
            {
                shapeObj.SetBoard((IBoard) Activator.CreateInstance(_configurationData[typeof (IBoard)]));
                return shapeObj;
            }

            return null;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            ShapeFactory.ConfigureContainer<IBoard, ConsoleBoard>();
            var shape = ShapeFactory.GetShape_UsingSetBoardMethod("NaiveFactory.Circle");
            var shape2 = ShapeFactory.GetShape_UsingConstructorInjection("NaiveFactory.Rectangle");
            shape.Draw();
            shape2.Draw();
            Console.ReadKey();
        }
    }
}
Aniket Inge
  • 25,375
  • 5
  • 50
  • 78
  • I think your comment to original post had much better text than you put in answer... Why not to use something close to IoC container as sample or just get all types implementing interface in current assembly? Hopefully would remove need for "terrible way to implement the factory" remark... – Alexei Levenkov Aug 02 '15 at 05:45
  • @AlexeiLevenkov sounds fair enough. Let me try – Aniket Inge Aug 02 '15 at 05:46
  • 1
    @AlexeiLevenkov better? – Aniket Inge Aug 02 '15 at 06:36
  • Could be buggy :-( :-( – Aniket Inge Aug 02 '15 at 06:40
  • 1
    Nice. Small enough to fit in SO answer (if OP needs real IoC container it is anyway better to use existing one). – Alexei Levenkov Aug 02 '15 at 07:08
  • @AlexeiLevenkov I agree...there are plenty of IoC containers that are production ready. – Aniket Inge Aug 02 '15 at 07:12
  • @Aniket Thanks for the example when i pasted this code into Visual studio why does this code give me an error { Debug.WriteLine(str); } and var assembly = Assembly.GetExecutingAssembly(); ... The error message is The name 'Assembly' and 'Debug' does not exist in the current context. –  Aug 02 '15 at 08:00
  • @LearningToCode that's because you haven't added the `using` statements. – Aniket Inge Aug 02 '15 at 08:01
0

Java version for this question

Code:

public class TestReflectionFactoryDesign {

    public static void main(String[] args) throws Exception {
        Person student = PersonFactory.getPersonWithFullQualifiedClassName("com.test.reflectionFactoryDesign.Student");
        student.say();
        Person teacher = PersonFactory.getPersonWithClass(Teacher.class);
        teacher.say();
        Person student2 = PersonFactory.getPersonWithName("student");
        student2.say();
    }
}

class Student implements Person {
    @Override
    public void say() {
        System.out.println("I am a student");
    }
}

class Teacher implements Person {
    @Override
    public void say() {
        System.out.println("I am a teacher");
    }
}

interface Person {
    void say();
}

class PersonFactory {
    // reflection, by full qualified class name
    public static Person getPersonWithFullQualifiedClassName(String personType) throws Exception {
        Class<?> personClass = Class.forName(personType);
        return getPersonWithClass(personClass);
    }

    // reflection, by passing class object
    public static Person getPersonWithClass(Class personClass) throws Exception {
        return (Person) personClass.newInstance();
    }

    // no reflection, the ordinary way
    public static Person getPersonWithName(String personType) {
        if (personType.equalsIgnoreCase("STUDENT")) {
            return new Student();
        } else if (personType.equalsIgnoreCase("TEACHER")) {
            return new Teacher();
        }

        return null;
    }
}

Output:

I am a student
I am a teacher
I am a student
Michael W.
  • 101
  • 8