Factory


The Factory is named as such, because its responsible, at the smallest unit, to create the concrete extension as defined by the MetaData. It correctly suggests that it could be a FactoryMethod (GoF), but equally it could also be another Pattern such as Adaptor or Proxy. Whether the Concrete class is created internally on the request of an internal framework object, or directly as "Please create concrete for me", depends on the Framework implementation requirement.

For example, consider a web service, which is composed of an object of interface IWebService. The MetaData is read and the calls are forwarded from the Web Service to the Concrete IWebService implementation. The code behind the web service may not be a FactoryMethod or AbstractFactory, but it will always have to Create the Instance, and that activity is called a Factory (according to this Pattern).

WhiteBox vs WhiteBox

The Factory can be either White or Black box in its implementation. However, special care must be taken for a whitebox approach.
The blackbox approach will allow you to simply instantiate the Concrete class, however with a whitebox you are going to relinquish certain parts of the responsibility, and thus certain amount of control to another implementation.

In the black box approach, you specify via explicit interface an object which implements it. This object or set of objects are then created internally by the framework, usually calling an initialize or starting method, to let the extension know it is being summoned.

In the white box approach, we can either load an extension which itself is a factory responsible for loading an extension that we know, or we can give context to the extensions factory and allow it to do what it must with the context. in both cases, the final extension that is loaded is 2 abstractions away from the framework code, thus making it more isolated, but less dependent.

A Factory with Intention

The intention of a Factory within a Framework can be for two distinct reasons. The first is to create an internal component that by decision, rule or configuration must be loaded. The second is to load the client code's custom implementation of a Framework hook or extension. The two intentions must remain clear and demarcated. Code should be explicitly one or the other, else your framework hooks can become soft and too abstract. There is a case for a blurring of the two intentions, but I have found that merging them has early rewards, but later disadvantages.

 

To create a Factory you can use many techniques and there are many libraries and samples. One particular technique I like is by specifying the Type, and getting a list of those types in a .NET Assembly that can be used. The following code is merely a 'start' to a small Factory class, to give an idea.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    public class Factory
    {
        #region Field/s

        private Dictionary _Types = new Dictionary();

        #endregion        
        
        #region Method/s

        public Factory(Assembly assembly)
        {
            Type[] types = Assembly.GetAssembly(typeof(T)).GetTypes();

            foreach (Type type in types)
            {
                if (!typeof(T).IsAssignableFrom(type) || type == typeof(T))
                {
                    continue;
                }

                _Types.Add(type.Name.ToLower(), type); //add to
            }
        }

        public virtual T CreateObject(Type type, params object[] args)
        {
            return (T)Activator.CreateInstance(type, args);
        }

        public virtual T CreateObject(string typeName, params object[] args)
        {
            if (!string.IsNullOrEmpty(typeName))
            {
                typeName = typeName.ToLower();
            }

            if (_Types.ContainsKey(typeName))
                return (T)Activator.CreateInstance(_Types[typeName], args);
            else
                return default(T);
        }

        #endregion

        #region Property/s

        public Dictionary Types
        {
            get
            {
                return _Types;
            }
            internal set
            {
                _Types = value;
            }
        }

        #endregion
    }
}


To get a sample running, you will need to create a console app and put the following code in place.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    public abstract class MyBase
    {

    }

    public class MyType : MyBase
    {
    }

    class Program
    {

        static void Main(string[] args)
        {
            Factory factory = new Factory(Assembly.GetExecutingAssembly());

            MyBase obj = (MyBase)factory.CreateObject("MyType", null);

            //or

            obj = (MyBase)factory.CreateObject(factory.Types["mytype"], null);
            
        }
    }
}