Design patterns (4 part series)
- Design patterns: Singleton
- Design patterns: Factory
- Design patterns: Observer
- Design patterns: Decorator
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 and 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.
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.
To achieve the factory pattern, there are 4 types of classes we need to implement:
Abstract Factory
class
Concrete Factory
subclasses
Create
method (these will instantiate the Factory
's Product
objects).Abstract Product
class
Product
properties and methods.Concrete Product
subclasses (these will be instantiated by the Factory objects)
Product
class and define the unique Product
types.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(){FactoryA a = new FactoryA();FactoryB b = new FactoryB();Console.WriteLine(a + " created " + a.Create().Name);Console.WriteLine(b + " created " + b.Create().Name);}}abstract class Factory{public abstract Product Create();}class FactoryA : Factory{public FactoryA(){}public override Product Create(){return new ProductA();}}class FactoryB : Factory{public FactoryB(){}public override Product Create(){return new ProductB();}}abstract class Product{public string Name {get; set;}}class ProductA : Product{public ProductA(){this.Name = "Pepsi";}}class ProductB : Product{public ProductB(){this.Name = "Coke";}}
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 HistoryBook
.
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 that the user decided to create (using the same code no matter what 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("Let's make a Novel");string bookType = "Novel"; // Try replacing this with "History"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 {}
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.