Design patterns in C# – part 11 (Abstract Factory pattern)

Role

This pattern supports the creation of products that exist in families and are designed to be produced together. The abstract factory can be refined to concrete factories, each of which can create different products of different types and in different combinations.

Design

AbstractFactoryPattern

Implementation

  • Client -> TestAbstractFactoryPattern
  • IFactory -> ICarFactory<TCarBrand>
  • Factory1, Factory2 -> CarFactory<TCarBrand>, (TCarBrand -> Toyota, Lexus)
  • IProductA, IProductB -> ISuv, ISedan
  • ProductA, ProductB -> Suv, Sedan
namespace AbstractFactoryPattern
{
    public interface ICarBrand
    {
        string SuvModelName { get; }
        uint SuvModelPrice { get; }
        WheelDrive SuvModelWheelDrive { get; }
        string SedanModelName { get; }
        uint SedanModelPrice { get; }
    }

    public interface ISuv
    {
        string Model { get; }
        uint Price { get; }
        WheelDrive Drive { get; }
    }

    public enum WheelDrive
    {
        Two,
        Four
    }

    public interface ISedan
    {
        string Model { get; }
        uint Price { get; }
    }

    public interface ICarFactory where TCarBrand : ICarBrand
    {
        ISuv CreateSuv();
        ISedan CreateSedan();
    }
}
namespace AbstractFactoryPattern
{
    public class Toyota : ICarBrand
    {
        #region ICarBrand Members

        public string SuvModelName
        {
            get { return "Toyota RAV4"; }
        }

        public uint SuvModelPrice
        {
            get { return 21500; }
        }

        public WheelDrive SuvModelWheelDrive
        {
            get { return WheelDrive.Two; }
        }

        public string SedanModelName
        {
            get { return "Toyota Corolla"; }
        }

        public uint SedanModelPrice
        {
            get { return 15300; }
        }

        #endregion
    }

    public class Lexus : ICarBrand
    {
        #region ICarBrand Members

        public string SuvModelName
        {
            get { return "Lexus RX10"; }
        }

        public uint SuvModelPrice
        {
            get { return 36800; }
        }

        public WheelDrive SuvModelWheelDrive
        {
            get { return WheelDrive.Four; }
        }

        public string SedanModelName
        {
            get { return "Lexus IS09"; }
        }

        public uint SedanModelPrice
        {
            get { return 31305; }
        }

        #endregion
    }
}
namespace AbstractFactoryPattern
{
    public class CarFactory : ICarFactory where TCarBrand : ICarBrand, new()
    {
        #region ICarFactory Members

        public ISuv CreateSuv()
        {
            return new Suv();
        }

        public ISedan CreateSedan()
        {
            return new Sedan();
        }

        #endregion
    }

    internal class Sedan : ISedan where TCarBrand : ICarBrand, new()
    {
        private readonly ICarBrand _carBrand;

        public Sedan()
        {
            this._carBrand = new TCarBrand();
        }

        #region ISedan Members

        public string Model
        {
            get { return this._carBrand.SedanModelName; }
        }

        public uint Price
        {
            get { return this._carBrand.SedanModelPrice; }
        }

        #endregion
    }

    internal class Suv : ISuv where TCarBrand : ICarBrand, new()
    {
        private readonly ICarBrand _carBrand;

        public Suv()
        {
            this._carBrand = new TCarBrand();
        }

        #region ISuv Members

        public string Model
        {
            get { return this._carBrand.SuvModelName; }
        }

        public uint Price
        {
            get { return this._carBrand.SuvModelPrice; }
        }

        public WheelDrive Drive
        {
            get { return this._carBrand.SuvModelWheelDrive; }
        }

        #endregion
    }
}
using System;

namespace AbstractFactoryPattern
{
    public class TestAbstractFatoryPattern
    {
        public static void Main(string[] args)
        {
            ICarFactory toyotaFactory = new CarFactory();
            ICarFactory lexusFactory = new CarFactory();

            ISuv toyotaSuv = toyotaFactory.CreateSuv();
            ISuv lexusSuv = lexusFactory.CreateSuv();

            Console.WriteLine("SUVs\n");

            Console.WriteLine("Toyota Suv: {0}, price: ${1}, it is {2}-Wheel-Drive.", toyotaSuv.Model, toyotaSuv.Price,
                              toyotaSuv.Drive);
            Console.WriteLine("Lexus Suv: {0}, price: ${1}, it is {2}-Wheel-Drive.", lexusSuv.Model, lexusSuv.Price,
                              lexusSuv.Drive);

            ISedan toyotaSedan = toyotaFactory.CreateSedan();
            ISedan lexusSedan = lexusFactory.CreateSedan();

            Console.WriteLine("\n\nSedans\n");

            Console.WriteLine("Toyota Sedan: {0}, price: ${1}.", toyotaSedan.Model, toyotaSedan.Price);
            Console.WriteLine("Lexus Sedan: {0}, price: ${1}.", lexusSedan.Model, lexusSedan.Price);
        }
    }
}

OUTPUT:

SUVs

Toyota Suv: Toyota RAV4, price: $21500, it is Two-Wheel-Drive.
Lexus Suv: Lexus RX10, price: $36800, it is Four-Wheel-Drive.

Sedans

Toyota Sedan: Toyota Corolla, price: $15300.
Lexus Sedan: Lexus IS09, price: $31305.

Use when

  • A system should be independent of how its products are created, composed, and represented.
  • A system can be configured with one of multiple families of products.
  • The constraint requiring products from the same factory to be used together must be enforced.
  • The emphasis is on revealing interfaces, not implementations.

Bibliography

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s