DEV Community

loading...
Cover image for Design Patterns: Factory

Design Patterns: Factory

ryhenness profile image Ryan ・3 min read

Yo yo! This is the second post that I'm writing as I'm starting to learn design patterns. My first post covered the Singleton pattern, you can find that here. This time we'll be taking a look at another creational pattern, the Factory pattern. Let's first visit the definition, then the implementation of the pattern, and finish with a look at some example code.


Overview


Definition

Factory: a building or group of buildings where goods are manufactured. Like I said earlier, the Factory pattern is a creational pattern and it gives us flexibility in creating different types of objects that inherit from the same class, and then use those objects within the same code.

We use a Factory and Product relationship to make up this pattern. The Factory takes care of instantiating the Products that it wants to produce, and the Products just need to know what rules they need to follow in order to be a product.


Implementation

To achieve the Factory pattern, there are 4 types of classes we need to implement:

  1. Abstract Factory class.
    • Defines an abstract Create method. In some cases, this may include a default implementation.
  2. Concrete Factory classes.
    • Implements the Create method (this will instantiate the Factory's Product objects).
  3. Abstract Product.
    • Defines the Product properties and methods.
  4. Concrete Product class (this will be instantiated by the Factory objects).
    • Inherits from the Product class, defines the unique Product.

This pattern allows us to defer the creation of the Product objects to the subclasses of Factory, making it a creational pattern that gives our code flexibility.

Using C#, the pattern looks like this:

using System;

public class Program
{
    public static void Main()
    {

    }
}

abstract class Factory
{
   public abstract Product Create();
}

class FactoryA : Factory
{
    public override Product Create()
    {
        return new ProductA();
    }
}

class FactoryB : Factory
{
    public override Product Create()
    {
        return new ProductB();
    }
}

abstract class Product
{
    public string Name;
}

class ProductA : Product
{
    public ProductA()
    {
        this.Name = "Pepsi";
    }
}

class ProductB : Product
{
    public ProductB()
    {
        this.Name = "Coke";
    }
}
Output:
FactoryA created Pepsi
FactoryB created Coke

You can play with this code here on .NET Fiddle


Example Code - Creating Books

Now let's take a look at a real world example. Perhaps we want to create a program that helps users create different types of Books. For now, this program will help the user create a Novel, or a History book. Novels will be composed of Pages: Title Page, Event, and About the Author. History books will be composed of Pages: Acknowledgments, Units, and Glossary. The program will then print out the Pages of the book they decided to create (using the same code no matter which book type that the user chose).

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Welcome to Book creator!");
        Console.WriteLine("Would you like to make a Novel or History book?");
        string bookType = Console.ReadLine();
        BookFactory bookFactory = new CoolBookFactory(bookType);
        Book userBook = bookFactory.Create();
        // The magic of the pattern is below:
        Console.WriteLine("PAGES -----");
        foreach (var page in userBook.pages)
        {
            Console.WriteLine(page.GetType().Name);
        }
    }
}

abstract class BookFactory
{
    public abstract Book Create();
}

class CoolBookFactory : BookFactory
{
    public string BookType { get; private set; }

    public CoolBookFactory(string bookType)
    {
        this.BookType = bookType;
    }

    public override Book Create()
    {
        if (this.BookType == "Novel")
            return new NovelBook();
        if (this.BookType == "History")
            return new HistoryBook();

        return null;
    }
}

abstract class Book
{
    public List<Page> pages = new List<Page>();
}

class NovelBook : Book 
{
    public NovelBook()
    {
        this.pages.Add(new TitlePage());
        this.pages.Add(new EventPage());
        this.pages.Add(new AboutTheAuthorPage());
    }
}

class HistoryBook : Book
{
    public HistoryBook()
    {
        this.pages.Add(new AcknowledgmentsPage());
        this.pages.Add(new UnitsPage());
        this.pages.Add(new GlossaryPage()); 
    }
}

abstract class Page {}
class TitlePage : Page {}
class EventPage : Page {} 
class AboutTheAuthorPage : Page {}
class AcknowledgmentsPage: Page {}
class UnitsPage : Page {} 
class GlossaryPage : Page {}
Output:
Welcome to Book creator!
Would you like to make a Novel or History book?
Novel
PAGES -----
TitlePage
EventPage
AboutTheAuthorPage

You can play with this code here on .NET Fiddle

You can see that we now have the flexibility of adding other Books and Pages without modifying the creation code written in our main class. To add other Books, all we would need to do is have the Factory class handle another book type.


Disclaimer: There are a lot of resources for learning design patterns, and they can be implemented in different ways. I would recommend exploring more resources when finished with this post.

Discussion

pic
Editor guide
Collapse
lukaszahradnik profile image
Lukáš Zahradník

I think your implementation of the CoolBookFactory is wrong.

public override Book Create()
{
    return this.userBook;
}

It should return new instance each time the method Create is called. Right now, it creates new instance of book in the contructor and returns the same instance on every Create call.

Collapse
ryhenness profile image
Ryan Author

Good catch, thanks a lot! :)

Collapse
aftabksyed profile image
Aftab Syed

So Ryan did you update your code with the rectified bug?

Thread Thread
ryhenness profile image