[X]

C# Abstract Factory Pattern - Design Patterns in Action

Abstract Factory Design Pattern

We have already seen about factory method design pattern. abstract factory is about grouping similar family of factory pattern and providing abstract layering for them.

The main motto of abstract factory design pattern is "Provide an interface for creating families of related or dependent objects without specifying their concrete classes." as specified in GoF. Below are the main members of this design pattern:

AbstractFactory - An interface with Get operations for each of the abstract products

Factory1, Factory2 - Implementations of all the AbstractFactory creation operations

AbstractProduct - An interface for a kind of product with its own operations

ProductA1, ProductA2, ProductB1, ProductB2 - Classes that implement the AbstractProduct interface and define product objects to be created by the corresponding factories

Client  - A class that accesses only the AbstractFactory and AbstractProduct interfaces

 

Collaboration: usually only one concretefactory instance, matched to a specific application context, is used for activation.It builds a specific product family for client use. The client or some other agent on behalf of client, may use the AbstractFactory for creation of objects.

Benefit:

  • It isolates concrete classes from the clients
  • AbstractFactory is used to control the classes of objects, client creates.
  • Product names are isolated in the implementation of the concrete factory, client uses the instances through their abstract interfaces
  • Promotes consistency among products
  • It is concrete factory job to make sure that right products are used together
  • Exchanging product faimilies is easy
  • None of the client breaks because the abstract interfaces dont change
  • Because the abstract factory creates a complete of products, the whole product family changes when the concrete factory has changed

Liability:

  • Adding new kind of product is diffcult becasue:
  • adding a new product requires extending the abstract interface which means all of its subclasses must also change
  • Essentially everything must change to support new product family addition:
  • abstract factory interface is extended
  • derived concrete factories must implement the extensions
  • a new product abstract class is added
  • a new product implementation is added
  • client has to be extended to use the new product

 

Difference between Factory and Abstract factory pattern:

The intent of Factory Method is "Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses."


So lets proceed further with the things in our previous Factory method pattern "Movie" example.

Client: looking for list of movies

AbstractFactory: IMovieFactory

Concrete FactoryA: returns movies from Hollywood and Bollywood for category/genre "A"

Concrete FactoryB: returns movies from Hollywood and Bollywood for category/genre "B"

AbstractProductA: IHollywoodMovie

Concrete ProductA1: HollywoodAnimation

Concrete ProductA2:  HollywoodComedy

AbstractProductB: IBollywoodMovie

Concrete ProductB1: BollywoodAnimation

Concrete ProductB2:  BollywoodComedy

1. Create a C# Library project which will contain all the Interfaces and Concrete classes.

2. Add MovieInterfaces.cs file with below code:

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

namespace AbstractFactoryPattern
{
    public interface IHollywoodMovie
    {
        string MovieName { get; }
    }

    public interface IBollywoodMovie
    {
        string MovieName { get; }
    }

    public interface IMovieFactory
    {
        IHollywoodMovie GetHollywoodMovie();
        IBollywoodMovie GetBollywoodMovie();
    }
}

 

3. Add ConcreteClasses.cs file with below code:

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

namespace AbstractFactoryPattern
{
    internal class HollywoodAnimation:IHollywoodMovie
    {
        public string MovieName { get { return "Shrek"; } }
    }

    internal class HollywoodComedy : IHollywoodMovie
    {
        public string MovieName { get { return "Step Mother"; } }
    }    
    
    internal class BollywoodAnimation:IBollywoodMovie
    {
        public string MovieName { get { return "The Ramayana"; } }
    }

    internal class BollywoodComedy : IBollywoodMovie
    {
        public string MovieName { get { return "Bombay to Goa"; } }
    }

    public class AnimationMovieFactory : IMovieFactory
    {
        public IHollywoodMovie GetHollywoodMovie()
        {
            return new HollywoodAnimation();
        }

        public IBollywoodMovie GetBollywoodMovie()
        {
            return new BollywoodAnimation();
        }
    }

    public class ComedyMovieFactory : IMovieFactory
    {
        public IHollywoodMovie GetHollywoodMovie()
        {
            return new HollywoodComedy();
        }

        public IBollywoodMovie GetBollywoodMovie()
        {
            return new BollywoodComedy();
        }
    }
}

 

 

4. Create a MoviesClient console application, add reference to Movies class library project.

5. Add below code to Program.cs file:

 

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

namespace MoviesClient
{
    class Program
    {
        static void Main(string[] args)
        {
            AnimationMovieFactory animationFactory = new AnimationMovieFactory();

            IHollywoodMovie ha = animationFactory.GetHollywoodMovie();
            IBollywoodMovie ba = animationFactory.GetBollywoodMovie();

            Console.WriteLine("Animation movies form Bollywood is\n\r {0} and from Hollywood is {1}",
                ba.MovieName, ha.MovieName);
            Console.ReadLine();

            ComedyMovieFactory comedyFactory = new ComedyMovieFactory();

            IHollywoodMovie hc = comedyFactory.GetHollywoodMovie();
            IBollywoodMovie bc = comedyFactory.GetBollywoodMovie();

            Console.WriteLine("Comedy movies form Bollywood is\n\r {0} and from Hollywood is {1}",
                bc.MovieName, hc.MovieName);
            Console.ReadLine();
        }
    }
}

 

 

In above example we can see that if we have to GetHorror movies from both Hollywood and Bollywood, we have to consistently and very carefully add -

  • Concrete factory class - HorrorMovieFactory
  • Concrete product classes - HollywoodHorror, BollywoodHorror

So this satisfies one of the basic idea behind abstract factory pattern that "Essentially everything must change to support new product family addition".

blog comments powered by Disqus

Posts By Month