﻿// See http://www.blackwasp.co.uk/AbstractFactory.aspx
// This design pattern is used to provide a client with a set of related or dependant objects. 
// Which objects are created is determined at run-time.
namespace BlackWasp.AbstractFactory
{
    /// <summary>
    /// This is the client class that creates the family of objects.
    /// </summary>
    internal class BasicClient
    {
        /// <summary>
        /// Create private properties for each of the objects that will be created by the factory.
        /// If these objects are only modified in the constructor then they could also be marked
        /// as readonly.
        /// The base class type is used as the actual types are unknown until runtime.
        /// </summary>
        private AbstractProductA _productA;
        private AbstractProductB _productB;

        /// <summary>
        /// The constructor initialises the properties using methods defined on the factory
        /// class that is passed as a parameter to the constructor.
        /// </summary>
        /// <param name="factory">Controls the type of objects that will be created. This will be
        /// a concrete implementation of an abstract base class.</param>
        public BasicClient(AbstractFactory factory)
        {
            _productA = factory.CreateProductA();
            _productB = factory.CreateProductB();
        }
    }

    /// <summary>
    /// This is the base class for the various factory objects that may be present in the system.
    /// Any classes that inherit this class will have to implement all the methods defined in it.
    /// Each object that should be supported by the factory should have an associated creation method.
    /// </summary>
    internal abstract class AbstractFactory
    {
        public abstract AbstractProductA CreateProductA();
        public abstract AbstractProductB CreateProductB();
    }

    /// <summary>
    /// One implementation of the factory. Each of the creation methods are overridden.
    /// </summary>
    internal class ConcreteFactoryA : AbstractFactory
    {
        public override AbstractProductA CreateProductA()
        {
            return new ProductA1();
        }

        public override AbstractProductB CreateProductB()
        {
            return new ProductB1();
        }
    }

    /// <summary>
    /// Another implementation of the factory. Each of the creation methods are overridden again 
    /// and this time different objects are returned.
    /// </summary>
    internal class ConcreteFactoryB : AbstractFactory
    {
        public override AbstractProductA CreateProductA()
        {
            return new ProductA2();
        }

        public override AbstractProductB CreateProductB()
        {
            return new ProductB2();
        }
    }

    /// <summary>
    /// A base class for a distinct type of product required by the client.
    /// </summary>
    internal abstract class AbstractProductA { }

    /// <summary>
    /// A concrete implementation which would contain specific functionality. Instances of this 
    /// and the other concrete implementations are generated by the abstract factory to populate
    /// the client.
    /// </summary>
    internal class ProductA1 : AbstractProductA { }
    internal class ProductA2 : AbstractProductA { }

    internal abstract class AbstractProductB { }
    internal class ProductB1 : AbstractProductB { }
    internal class ProductB2 : AbstractProductB { }
}
