Click here to Skip to main content
Click here to Skip to main content

Factory Method Design Pattern

, 4 May 2011
Rate this:
Please Sign up or sign in to vote.
Factory Method Design Pattern Clearly Explained with Example

You can see this and other great articles on Design Patterns here.

The Factory Method Design Pattern allows you to create objects without being bothered on what is the actual class being created. The benefit is that the client code (calling code) can just say "give me an object that can do XYZ" without knowing what is the actual class that can do "XYZ".

Let's do an example to see how it works. Let’s say you are an online bookstore and people come to your website to buy books. When a customer orders a book, you just have another book distributor send the book directly to the customer. You are a middle man and you don’t stock the books. You have many distributors that you can choose to send the books directly to your customers.

Since you have many distributors, you have the following logic to determine which distributor to choose for sending the books to your customers:

  • If the customer is in the east coast, you will use EastCoastDistributor
  • If the customer is in the mid-west, you will use MidWestDistributor
  • If the customer is in the west coast, you will use WestCoastDistributor

The key is your customer should not care which distributor you choose because they will get their books regardless. It is completely hidden from the customer's point of view, and they should not be concerned about it. You, the online bookstore, are the one that determines the distributor to use.

Using this example, we can have the following UML:

The logic that decides which distributor to use is in the BookStore.GetDistributor method. The method returns IDistributor with the following logic:

  • If the customer is in the east coast, return EastCoastDistributor
  • If the customer is in the mid-west, return MidWestDistributor
  • If the customer is in the west coast, return WestCoastDistributor

This method is the factory method that returns a product (a distributor). Each of the distributor implements the IDistributor interface, which has the ShipBook method. The client code just says "give me a distributor that can ShipBook" without having to know which distributor you are going to return.

You can now have client code (calling code) such as:

IDistributor b = bookStore.GetDistributor();
//the client gets the distributor without having
//to know which distributor is being used

Notice that this client code don’t need to care which distributor is being created, and this is key to the Factory Method pattern.

Taking another step further, we can abstract out the BookStore as an interface and have more types of bookstores, as shown below:

Now you can have client code such as the following that does not need to be changed if the logic for choosing the distributor changes:

//this client code will not need to be changed even
//if the logic for the distributor changed
public void ShipBook(IBookStore s)    
{        
    IDistributor d = s.GetDistributor();
    d.ShipBook();
}

You can pass in any bookstore that implements the IBookStore interface to this method and it will use the correct distributor automatically. The benefit is that this client code does not need to be changed when you change the logic of the GetDistributor method of the bookstores.

Below is the UML of the Factory Method Design Pattern, which is what we have in our example:

 

Below are the implementation code and the output of the Factory Method pattern using our example. Notice that you can change the code in the factory without changing the client code for the factory to produce different products (distributors):

public enum CustomerLocation { EastCoast, MidWest, WestCoast }
class Program
{     
    static void Main(string[] args)
    {
        Console.WriteLine("East Coast Customer:");
        IBookStore bookstore = new BookStoreA(CustomerLocation.EastCoast);
        ShipBook(bookstore);

        Console.WriteLine("Mid West Customer:");
        bookstore = new BookStoreA(CustomerLocation.MidWest);
        ShipBook(bookstore);

        Console.WriteLine("West Coast Customer:");
        bookstore = new BookStoreA(CustomerLocation.WestCoast);
        ShipBook(bookstore);
    }

    //**** client code does not need to be changed  ***
    private static void ShipBook(IBookStore s)
    {
        IDistributor d = s.GetDistributor();
        d.ShipBook();
    }
}

//the factory
public interface IBookStore
{
    IDistributor GetDistributor();
}

//concrete factory
public class BookStoreA : IBookStore
{
    private CustomerLocation location;

    public BookStoreA(CustomerLocation location)
    {
        this.location = location;
    }

    IDistributor IBookStore.GetDistributor()
    {
        //internal logic on which distributor to return
        //*** logic can be changed without changing the client code  ****
        switch (location)
        {
            case CustomerLocation.EastCoast:
                return new EastCoastDistributor();
            case CustomerLocation.MidWest:
                return new MidWestDistributor();
            case CustomerLocation.WestCoast:
                return new WestCoastDistributor();
        }
        return null;
    }
}

//the product
public interface IDistributor
{
    void ShipBook();
}

//concrete product
public class EastCoastDistributor : IDistributor
{
    void IDistributor.ShipBook()
    {
        Console.WriteLine("Book shipped by East Coast Distributor");
    }
}

//concrete product
public class MidWestDistributor : IDistributor
{
    void IDistributor.ShipBook()
    {
        Console.WriteLine("Book shipped by Mid West Distributor");
    }
}

//conceret product
public class WestCoastDistributor : IDistributor
{
    void IDistributor.ShipBook()
    {
        Console.WriteLine("Book shipped by West Coast Distributor");
    }
}

Liked this article? You can see this and other great articles on Design Patterns here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

DevLake

United States United States
No Biography provided

Comments and Discussions

 
General[My vote of 1] Tell us something new PinmemberMember 456543324-Apr-11 4:13 
GeneralOK Article Pinmemberjaimi21-Apr-11 8:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 4 May 2011
Article Copyright 2011 by DevLake
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid