[X]

C# Factory Pattern - Design Patterns in Action

Factory Method Pattern


Factory method pattern is a very light weight pattern. It is used in the scenarios where we do not want the client directly refer to the concrete classes for object instantiation, rather we handover the responsibility to a "Creator" class which will be instantiating the appropriate object based on the client requirement and thus centralizing the code of object creation. And client deals with interface instead of concrete classes. Factory method is also termed as "Virtual Constructor" in C++.

Intent & Motivation of Factory Pattern: "Define an interface for creating an object, but let subclasses decide which class to instantiate." Since library knows when an object needs to be created, but not what kind of object is going to be created. As this is specific to the application it can use the Factory Method.


Factory pattern is used when:

  • Flexibility is important.
  • Objects can be extended in subclasses
  • There is a specific reason why one subclass would be chosen over another. This logic forms part of the Factory Method.

We can think of below scenarios where Factory method pattern can be implemented:

 

  1. Set upa system to draw circles, squares, and lines. Create a Factory Method that instantiates one of these classes at random and uses it to draw a shape of random size on the screen. Run the program to see what interesting shapes you get.

  2. A company has a web site to display test results from a plain text file. The company recently purchased a new computer that produces a binary data file, and it has another new machine on the way that will possibly produce a different data file. The company is also considering switching to an XML format. Write a system to deal with such changes. The web site just needs data to display; your job is to provide the specified data format for the web site.

  3. We have list of movies categorized into genre. Client wants to get the specific genre movies. Here client can deal with movie interface and based on his parameter passed to FactoryMethod he will get the list of movies.


So let us work on the 3rd movie list example.

1. Create a "Movies" class library project which will consists of IMovie interface, Movie concrete classes, MovieCreator class with MovieFactoryMethod.


IMovie interface:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;


namespace FactoryPattern.Movies

{

    public interface IMovie

    {

        string MovieName { get; set; }

        List<IMovie> GetMovies();

    }



}


AnimationMovie concrete class:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace FactoryPattern.Movies

{

    internal class AnimationMovie:IMovie

    {

        public string MovieName { get; set; }



        public AnimationMovie()

        {



        }

        public AnimationMovie(string movieName)

        {

            MovieName = movieName;

        }



        public List<IMovie> GetMovies()

        {

            List<IMovie> movies = new List<IMovie>();

            movies.Add(new AnimationMovie("Finding Nemo"));

            movies.Add(new AnimationMovie("Monster Inc"));

            return movies;

        }

    }

}


ComedyMovie concrete class:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace FactoryPattern.Movies

{

    internal class ComedyMovie:IMovie

    {

        public string MovieName { get; set; }



        public ComedyMovie()

        {



        }

        public ComedyMovie(string movieName)

        {

            MovieName = movieName;

        }



        public List<IMovie> GetMovies()

        {

            List<IMovie> movies = new List<IMovie>();

            movies.Add(new ComedyMovie("Joe Almighty"));

            movies.Add(new ComedyMovie("Step Brother"));

            return movies;

        }

    }

}


ScienceFictionMovie concrete class:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace FactoryPattern.Movies

{

    internal class ScienceFictionMovie:IMovie

    {

        public string MovieName { get; set; }



        public ScienceFictionMovie()

        {



        }

        public ScienceFictionMovie(string movieName)

        {

            MovieName = movieName;

        }



        public List<IMovie> GetMovies()

        {

            List<IMovie> movies = new List<IMovie>();

            movies.Add(new ScienceFictionMovie("Matrix"));

            movies.Add(new ScienceFictionMovie("Jurassic Park"));

            return movies;

        }

    }

}

 

 


MovieCreator factory method class:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace FactoryPattern.Movies

{

    public class MovieCreator

    {

        public enum MovieGenre

        {

            ScienceFiction,

            Animation,

            Comedy

        }



        public IMovie FactoryMethod(MovieGenre genre)

        {

            IMovie movie=null;

            switch (genre)

            {

                case MovieGenre.Animation:

                    movie = new AnimationMovie();

                    break;

                case MovieGenre.Comedy:

                    movie = new ComedyMovie();

                    break;

                case MovieGenre.ScienceFiction:

                    movie = new ScienceFictionMovie();

                    break;

                default:

                    movie = new AnimationMovie();

                    break;

            }



            return movie;

        }

    }

}

 

 

We can see that "Concrete Movie" classes are marked as internal class, this way they will not be accessible to client. client will only have access to "IMovie" interface and it does need to know the underlying object creation mechanism.


2. Create a "MovieClient" console application project and add a reference to the Movies project. Use factory method to get the list of movies for different genres and test it.

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using FactoryPattern.Movies;

namespace MoviesClient

{

    class Program

    {

        static void Main(string[] args)

        {

            MovieCreator creator = new MovieCreator();



           //concrete classes are not available to the client

           

            //getting animation movies

            IMovie animationMovie = creator.FactoryMethod(MovieCreator.MovieGenre.Animation);

            List<IMovie> movies = animationMovie.GetMovies();

            Console.WriteLine("Animation movies:");

            foreach (IMovie movie in movies)

            {

                Console.WriteLine("{0}", movie.MovieName);

            }

            Console.WriteLine("------------------------------");

            Console.WriteLine();

            Console.WriteLine("Comedy movies:");

            //getting comedy movies

            IMovie comedyMovie=creator.FactoryMethod(MovieCreator.MovieGenre.Comedy);

            movies = comedyMovie.GetMovies();

            foreach (IMovie movie in movies)

            {

                Console.WriteLine("{0}", movie.MovieName);

            }



            Console.ReadLine();





        }

    }

}

 

 

To summarize we just saw that how object creation responsibility can be handled from FactoryMethod when all the subclasses are implementing the same base class. And also client can be least bothered about the concrete classes and can only deal with interface get its job done.

blog comments powered by Disqus

Posts By Month