Object Oriented Programming Patterns for Geeks

The Provider Factory

This isn't a GoF pattern in and of itself.  However because this crops up so often I felt it deserved a place here.  This pattern makes use of the Bridge pattern to allow the 'concrete creator' to exhibit different characteristics depending on the 'implementor' or 'provider' fed to it.

The above in english essentially means that you can interchange the machinery of the factory depending on what product you want to create while keeping the basic structure of the factory and it's use intact. 

This pattern actually is not too far removed from the Abstract Factory, except where-as with the Abstract Factory pattern you supply a Concrete Creator to a client object for it to consume and use as required, this variation supplies an 'implementor' which (most likely) contains  a Concrete Creator for the factory to use when you ask it to manufacture an object for you.  You can then if you so choose, supply the Factory that utiliises the supplied Implementor to a client object as per Abstract Factory.

This pattern is used in DATS to supply DAL operations to the library.

namespace ooppatterns
{
    using System;
    using System.Collections.Generic;

    internal class Program
    {
        private static void Main( string[] args )
        {

            List<IAbstractProduct> aList = new List<IAbstractProduct>();

            MethodFactory factory = new MethodFactory();
            factory.Implementor = new ContextProviderA();

            for ( int i = 0; i < 35; i++ )
            {
                if(i == 12)
                    factory.Implementor = new ContextProviderB();
                else if( i==20)
                    factory.Implementor = new ContextProviderA();
                else if ( i == 30 )
                    factory.Implementor = new ContextProviderB();

                aList.Add( factory.Create( i ) );
            }

            foreach ( IAbstractProduct ID in aList )
                ID.DoSomething();

            Console.ReadLine();
        }
    }

    // Providers or Implementor's from the Bridge pattern
    interface IProviderFactory
    {
        IAbstractFactory GetConcreteFactory( );
    }

    class ContextProviderA : IProviderFactory
    {
        public IAbstractFactory GetConcreteFactory()
        {
            return new ConcreteFactoryA();
        }
    }

    class ContextProviderB : IProviderFactory
    {
        public IAbstractFactory GetConcreteFactory(  )
        {
            return new ConcreteFactoryB();
        }
    }

    // Factories...
    interface IAbstractFactory
    {
        IAbstractProduct CreateProduct( int manufactureCriteria );
    }

    class ConcreteFactoryA : IAbstractFactory
    {
        public IAbstractProduct CreateProduct( int manufactureCriteria )
        {
            if ( manufactureCriteria % 15 == 0 )
                return new Example01( "This is created using MOD 15  FIZZBANG" );

            if ( manufactureCriteria % 5 == 0 )
                return new Example02( "This is created using MOD 5   FIZZ" );

            if ( manufactureCriteria % 3 == 0 )
                return new Example03( "This is created using MOD 3   BANG" );

            return new Example00( manufactureCriteria.ToString() );

        }
    }

    class ConcreteFactoryB : IAbstractFactory
    {
        public IAbstractProduct CreateProduct( int manufactureCriteria )
        {
            if ( manufactureCriteria % 13 == 0 )
                return new Example03( "This is created using MOD 13  Wibble" );

            if ( manufactureCriteria % 10 == 0 )
                return new Example01( "This is created using MOD 10  Wobble" );

            if ( manufactureCriteria % 7 == 0 )
                return new Example02( "This is created using MOD 7   Wubble" );

            return new Example00( manufactureCriteria.ToString() );
        }
    }

    // 'Abstraction' or 'Refined Abstraction' from the Bridge pattern
    class MethodFactory
    {
        private IProviderFactory _myPF;

        public IProviderFactory Implementor
        {
            set
            {
                this._myPF = value;
            }
        }

        public IAbstractProduct Create( int manufactureCriteria )
        {
            if ( this._myPF == null )
                throw new NullReferenceException();

            IAbstractFactory IAF = this._myPF.GetConcreteFactory();

            return IAF.CreateProduct( manufactureCriteria );
        }
    }

    // Products...
    interface IAbstractProduct
    {
        void DoSomething();
    }

    // Concrete Product 00
    class Example00 : IAbstractProduct
    {
        private string _value;

        public Example00( string value )
        {
            this._value = value;
        }

        public void DoSomething()
        {
            Console.WriteLine(  "Example00 : {0}", this._value ); 
        }
    }

    // Concrete Product 01
    class Example01 : IAbstractProduct
    {
        private string _value;

        public Example01( string value )
        {
            this._value = value;
        }

        public void DoSomething()
        {
            Console.WriteLine( "Example01 : {0}", this._value );
        }
    }

    // Concrete Product 02
    class Example02 : IAbstractProduct
    {
        private string _value;

        public Example02( string value )
        {
            this._value = value;
        }

        public void DoSomething()
        {
            Console.WriteLine("Example02 : {0}", this._value );
        }
    }

    // Concrete Product 03
    class Example03 : IAbstractProduct
    {
        private string _value;

        public Example03( string value )
        {
            this._value = value;
        }

        public void DoSomething()
        {
            Console.WriteLine( "Example03 : {0}", this._value ); 
        }
    }
}

 



[1/16/2008] Anon: Ref: providerfactory

Another way to do this would be to use generics to create a single point to get access to all providers. e.g.

public static class ProviderFactory<T>
{
   public static T Get()
   {
       //Load the provider based on the interface type via config or just use explict code
      if(typeof(T) == typeof(ICustomerProvider)
         return new ConcreteCustomerProvider();
      if(typeof(T) == typeof(IProductProvider)
         return new ProductProvider();
 
      return null;
   }
}
 
public interface ICustomerProvider
{
   Customer GetCutomer(int id);
}
public interface IProductProvider
{
   Product GetProduct(int id);
}
 
usage example:
 
public void DisplayProductDetails(int custId)
{
   Product p = ProviderFactory<ICustomerProvider>.Get().GetCustomer(custId);
 
   //Do some rendering with the instance.

}