Wednesday, October 10, 2012

Abstract Factory Pattern

*Disclaimer these writings are for my own learning purposes not as advice to others. If any part is incorrect please feel free to constructively discuss. 

Previously I discussed the Strategy Pattern and the Factory Pattern. Most recently I've been looking at the Abstract Factory Pattern.

Here's the general definition used throughout the internet:
The abstract factory pattern is considered a creational pattern. In general this pattern is most useful when a client needs to create a family of related or dependent objects without specifying the concrete class.

A common example is a drawing or UI framework. An abstract Factory Pattern might be used to create a family of brushes or a palette of colors.

The client knows about the abstract product, but it doesn't know or care about the the concrete classes created by the methods exposed by the abstract factory.

Abstract factory pattern can be a way to encapsulate concrete factories with commonalities. If the system needs to create multiple families or a library of products without being concerned with implementation details, then this patten can be used.

Here's my example using the vehicle theme again.

//The abstract factory
abstract class AbstractFactory
    {
        public abstract Car CreateCar();
        public abstract Truck CreateTruck();
    }

//The concrete factories implementing the interface defined by the abstract factory
class BaseModelFactory : AbstractFactory
    {
        public override Car CreateCar()
        {
            return new BaseModelCar();
        }
        public override Truck CreateTruck()
        {
            return new BaseModelTruck();
        }
    }

class FullyLoadedFactory : AbstractFactory
    {
        public override Car CreateCar()
        {
            return new FullyLoadedCar();
        }
        public override Truck CreateTruck()
        {
            return new FullyLoadedTruck();
        }
    }

class SportModelFactory : AbstractFactory
    {
        public override Car CreateCar()
        {
            return new SportModelCar();
        }
        public override Truck CreateTruck()
        {
            return new SportTruck();
        }
    }

//Abstract Product 1
abstract class Car
    {
        public abstract Seats Seat { get; }
        public abstract Trims Trim { get; }
        public abstract AccessoriesPackages AccessoriesPackage { get; }
        public abstract Engines Engine { get; }
        public abstract int GetTrunkSpace();
        public abstract string GetTitle();
    }

//Abstract product 2
abstract class Truck
    {
        public abstract Seats Seat { get; }
        public abstract Trims Trim { get; }
        public abstract AccessoriesPackages AccessoriesPackage { get; }
        public abstract Engines Engine { get; }
        public abstract int GetBedSpace();
        public abstract string GetTitle();
    }

//Concrete Products
class BaseModelCar : Car
    {
        public override Seats Seat
        {
            get { return Seats.Cloth; }
        }

        public override Trims Trim
        {
            get { return Trims.Base; }
        }

        public override AccessoriesPackages AccessoriesPackage
        {
            get { return AccessoriesPackages.Base; }
        }

        public override Engines Engine
        {
            get { return Engines.Economy; }
        }

        public override int GetTrunkSpace()
        {
            return 3 * 2;
        }

        public override string GetTitle()
        {
            return "a reliable dependable no frills base model sedan.";
        }
    }

class BaseModelTruck : Truck
    {
        public override Seats Seat
        {
            get { return Seats.Cloth; }
        }

        public override Trims Trim
        {
            get { return Trims.Base; }
        }

        public override AccessoriesPackages AccessoriesPackage
        {
            get { return AccessoriesPackages.Base; }
        }

        public override Engines Engine
        {
            get { return Engines.Economy; }
        }

        public override int GetBedSpace()
        {
            return 8 * 4 * 2;
        }

        public override string GetTitle()
        {
            return "a reliable dependable no frills base model truck.";
        }
    }

class FullyLoadedCar : Car
    {
        public override Seats Seat
        {
            get { return Seats.Leather; }
        }

        public override Trims Trim
        {
            get { return Trims.ChromePackage; }
        }

        public override AccessoriesPackages AccessoriesPackage
        {
            get { return AccessoriesPackages.FullyLoaded; }
        }

        public override Engines Engine
        {
            get { return Engines.Touring; }
        }

        public override int GetTrunkSpace()
        {
            return 4 * 3;
        }

        public override string GetTitle()
        {
            return "a top of the line state of the art fully loaded car.";
        }
    }

class FullyLoadedTruck : Truck
    {
        public override Seats Seat
        {
            get { return Seats.Leather; }
        }

        public override Trims Trim
        {
            get { return Trims.ChromePackage; }
        }

        public override AccessoriesPackages AccessoriesPackage
        {
            get { return AccessoriesPackages.FullyLoaded; }
        }

        public override Engines Engine
        {
            get { return Engines.Touring; }
        }

        public override int GetBedSpace()
        {
            return 6 * 4 * 2;
        }

        public override string GetTitle()
        {
            return "a top of the line state of the art fully loaded truck.";
        }
    }



And it goes on the same for sport car/truck.
*I could have flipped this example and made the abstract product be the package type (Fully loaded, Base Sport). Then I could have let the different vehicle types be the concrete products. In the end my client could have then said show my all the types of trucks, and I could have used the abstract factory to create a truck of type fully loaded, Base, and Sport.

*Note my code implies the use of some enums. I did not show the definition of the enums in the code snippets in this blog, but they are in the source code
.
Here is the source code complete with an example of a client calling the methods exposed by the abstract factory, and listing out the vehicles features.
DesignPatternExamples

No comments:

Post a Comment