Creating software is a challenging task.
With every new project, you must think of how to solve different problems in code so you can build the new project in the easiest manner possible. But working with code can sometimes feel like a puzzle, doesn’t it?
Luckily, this is where design patterns can help.
Design patterns are ways to handle code-related issues in your programs by creating standard solutions. As a result, they allow you to build software more efficiently.
Creational design patterns are a set of patterns that allow you to create objects in a controlled way. This is useful when you want to ensure that your objects are created in a specific way or when you want to avoid creating objects manually.
The creational patterns are the following:
- Abstract Factory pattern
- Builder pattern
- Factory Method pattern
- Prototype pattern
- Singleton pattern
This article will describe five creational design patterns you can use in your projects. Keep reading if you are curious to learn more about creational design patterns!
What are design patterns?
A design pattern is a repeatable solution to a commonly occurring problem in software development. A design pattern isn’t a finished design that you can copy and paste directly into code. Instead, it is a description or template for solving a problem that you can use in many different situations.
Design patterns provide detailed solutions that you can apply in real-world scenarios. In addition, they are written in specific language terminology so developers can easily understand them with different experience levels. That’s why you can also use them as a communication tool when discussing design decisions and architectural issues with others.
As a result, you don’t have to reinvent the wheel when encountering a common software design problem. Instead, you can use an existing design pattern to save time and effort.
In 1994, Erich Gamma, Richard Help, Ralph Johnson, and John Vlissides, also known as the Gang of Four, compiled a list of 23 design patterns and published them in the Design Patterns: Elements of Reusable Object-Oriented Software book. The book became a bestseller, read by millions of developers worldwide, and an all-time classic.
Another book related to design patterns that is very popular is Head First Design Patterns. It explains the design patterns in a very casual and interesting way. So I would definitely recommend reading that book as well, in addition to the original Design Patterns book.
The Gang of Four divided the design patterns into three categories:
- Creational design patterns – These are patterns that deal with object creation.
- Structural design patterns – These are patterns for how you can structure your code to make it more efficient, scalable, and maintainable.
- Behavioral design patterns – These are patterns that deal with the communication between objects. In other words, they define how objects interact with each other.
Let’s dive deeper into creational design patterns.
What are creational design patterns?
Creational design patterns are concerned with the object creation mechanism, i.e., the instantiation process. Their main idea is to hide the object creation process from the user and provide a flexible way to create objects.
We will cover the creational patterns later in the articles, but all these patterns have different approaches to solving the object creation problem. Still, they share one thing in common – they abstract away the object creation process from the user.
Creational design patterns become more important as the system evolves since they give the software more flexibility to change. In addition, they are helpful when a system must be independent of how its objects are created.
For example, an application needs to work with different types of databases. The majority of the code doesn’t have to know how database connections are instantiated and maintained. The application only needs to know how to work with them. In this case, you could use the Abstract Factory pattern.
Other times, it might be necessary for the system to know about the concrete classes used to instantiate objects. In that case, the Factory Method or Builder pattern would be more appropriate.
Creational patterns are further divided into object-creational and class-creational patterns. Object-creational patterns deal with direct object instantiation, while class-creational work with inheritance and object composition to delegate responsibility for object creation elsewhere in the code.
Abstract Factory pattern
The Abstract Factory design pattern is a creational design pattern that you can use to create families of related objects without specifying their concrete classes. This is done by creating a separate abstract factory for each family of objects.
For example, let’s say you have a family of objects that you use to represent cars. You might have a car factory that can create cars of various types, such as Sedans, Coupes, SUVs, etc. Each type of car would have its concrete class.
However, if you want to create families of related objects, such as a family of cars that includes Sedans, Coupes, SUVs, etc., you need to use the Abstract Factory. This would allow you to create a family of cars without specifying the concrete classes for each type of car.
The Abstract Factory design pattern is a powerful tool that you can use to simplify the creation of complex object hierarchies. It is handy when you need to create objects that are related to each other.
The following sample represents the structural code in C#.
namespace AbstractFactoryPattern;
/// Create our Abstract Factory:
abstract class AbstractFactory
{
public abstract AbstractProductI CreateProductI();
public abstract AbstractProductII CreateProductII();
}
class ConcreteFactoryI : AbstractFactory
{
public override AbstractProductI CreateProductI()
{
return new FirstProductOfAbstractI();
}
public override AbstractProductII CreateProductII()
{
return new FirstProductOfAbstractII();
}
}
class ConcreteFactoryII : AbstractFactory
{
public override AbstractProductI CreateProductI()
{
return new SecondProductOfAbstractI();
}
public override AbstractProductII CreateProductII()
{
return new SecondProductOfAbstractII();
}
}
/// Our First Abstract Product
abstract class AbstractProductI
{
}
/// Our Second Abstract Product
abstract class AbstractProductII
{
public abstract void Interact(AbstractProductI i);
}
class FirstProductOfAbstractI : AbstractProductI
{
}
class FirstProductOfAbstractII : AbstractProductII
{
public override void Interact(AbstractProductI i)
{
Console.WriteLine(this.GetType().Name +
" is linking with " + i.GetType().Name);
}
}
class SecondProductOfAbstractI : AbstractProductI
{
}
class SecondProductOfAbstractII : AbstractProductII
{
public override void Interact(AbstractProductI i)
{
Console.WriteLine(this.GetType().Name +
" is linking with " + i.GetType().Name);
}
}
class Client
{
private AbstractProductI _abstractProductI;
private AbstractProductII _abstractProductII;
public Client(AbstractFactory factory)
{
_abstractProductI = factory.CreateProductI();
_abstractProductII = factory.CreateProductII();
}
public void Run()
{
_abstractProductII.Interact(_abstractProductI);
}
}
If you want to learn more about the Abstract Factory pattern, see a real-world code example, then check out the separate article.
Builder pattern
The Builder design pattern is a creational design pattern that allows for the construction of complex objects to be created in a step-by-step fashion.
The Builder pattern is often used when creating objects with:
- many dependencies,
- many properties
- or when the exact details of the object are not known ahead of time.
This pattern is also helpful when you want to give the client complete control over the construction process.
For example, if you were building a house, you would first need to lay the foundation, then add the walls and roof. The Builder design pattern would allow you to build this house one step at a time without worrying about each step’s details.
By following this pattern, you can create complex objects without needing to understand all of the details upfront.
The following sample represents the structural code in C#.
class Director
{
private IBuilder _builder;
public Director(IBuilder builder)
{
_builder = builder;
_builder.BuildPart1();
_builder.BuildPart2();
Product finishedProduct = _builder.Build();
}
}
interface IBuilder
{
void BuildPart1();
void BuildPart2();
Product Build();
}
class ConcreteBuilder : IBuilder
{
private Product _product;
public ConcreteBuilder()
{
_product = new Product();
}
public void BuildPart1()
{
_product.Part1 = "part1";
}
public void BuildPart2()
{
_product.Part2 = "part2";
}
public Product Build()
{
return _product;
}
}
public class Product
{
public string Part1 { get; set; }
public string Part2 { get; set; }
}
If you want to learn more about the Builder pattern, see a real-world code example, then check out the separate article.
Factory Method pattern
The Factory design pattern is one of the most popular programming patterns. The Factory Method defines an interface for creating an object but lets subclasses decide which class to instantiate. This is useful when you don’t know what kind of object you need to create ahead of time.
The specific type of object that is returned can be determined based on input parameters, making the Factory Method highly flexible.
You can use the Factory Method design pattern when you need to create objects that are related to a common theme (e.g., sports equipment, vehicles, etc.). It allows you to define a common interface for all the objects you want to create but allows each subclass to choose the concrete implementation.
For example, let’s say you want to create a class representing a vehicle. You could have a base class called Vehicle and then subclasses for Car, Truck, Motorcycle, etc. Each of these subclasses would override the methods in the Vehicle base class to provide their own implementation.
The Factory Method interface would define a method that returns a Vehicle type. Then, the concrete Factory Method implementation class would contain the creation logic in it. This would allow you to vary a Vehicle object instance at runtime, depending on which subclass you want to use.
When it makes sense in your code, you could use a factory class or method instead of calling the constructor because the factory method can:
- be more flexibly named,
- return a subclass instance,
- return an existing object instead of creating a new one,
- give more control over the instantiation process.
This article explains when to use the Factory Method instead of the constructor. It also explains why you should stick with a simple constructor in most cases.
The following sample represents the structural code in C#.
//interface for creating the objects
interface IProduct
{
}
//Concrete Product 1, whose object is created
class ConcreteProduct1 : IProduct
{
}
//Concrete Product 2, whose object is created
class ConcreteProduct2 : IProduct
{
}
//The Creator has a Factory Method.
//This class is actually responsible for creating objects.
abstract class Creator
{
public abstract IProduct FactoryMethod(int product_number);
}
//Concrete Creator will create the objects
//according to the product number passed to the Factory Method.
class ConcreteCreator : Creator
{
public override IProduct FactoryMethod(int product_number)
{
switch (product_number)
{
case 1:
return new ConcreteProduct1();
case 2:
return new ConcreteProduct2();
default:
Console.Write("Invalid Product number");
return null;
}
}
}
If you want to learn more about the Factory Method pattern, see a real-world code example, then check out the separate article.
Prototype pattern
The Prototype design pattern is a creational design pattern used to instantiate new objects by copying an existing object. The prototype object serves as a template for creating new objects. This allows you to create new objects without the need for expensive and time-consuming operations.
The Prototype design pattern is also handy when creating large numbers of objects.
When using the Prototype design pattern, it is essential to remember that the prototype object itself must be cloneable. That is, it must be possible to create a new object by copying the prototype object.
The following sample represents the structural code in C#.
public interface IPrototype
{
string Name { get; set; }
IPrototype Clone();
}
public class ConcretePrototype1 : IPrototype
{
public ConcretePrototype1(string name)
{
Name = $"{name} cloned from ConcretePrototype1";
}
public string Name { get; set; }
public IPrototype Clone()
{
return (IPrototype)this.MemberwiseClone();
}
}
public class ConcretePrototype2 : IPrototype
{
public ConcretePrototype2(string name)
{
Name = $"{name} cloned from ConcretePrototype2";
}
public string Name { get; set; }
public IPrototype Clone()
{
return (IPrototype)this.MemberwiseClone();
}
}
If you want to learn more about the Prototype pattern, see a real-world code example, then check out the separate article.
Singleton design pattern
The Singleton design pattern is a creational design pattern that allows for the instantiation of a class to have only one object. It is useful when an application needs to have one point of access to an instance of a class.
The Singleton design pattern is implemented by creating a static instance of the class in question and providing a static method that returns the instance. This ensures that only one instance can be created and that the instance can be accessed from anywhere in the code.
While the Singleton design pattern is helpful in some situations, you should use it with caution, as it can lead to code that is difficult to maintain and test.
It is not a bad pattern, but you need to be careful not to misuse it.
The following sample represents the most straightforward implementation of Singleton in C#.
public sealed class SingletonPattern
{
private static SingletonPattern instance = null;
//private constructor
private SingletonPattern()
{ }
//property to access the Instance
public static SingletonPattern Instance
{
get
{
//checking if the Instance already exists
if (instance == null)
{
instance = new SingletonPattern();
}
return instance;
}
}
}
If you want to learn more about the Singleton pattern and see 5 other implementations of the Singleton pattern that are more thread-safe, check out this separate article.
Conclusion
There are many different design patterns, and each can be useful in different situations.
This article explored creational design patterns: Abstract Factory, Builder, Factory Method, Prototype, and Singleton patterns.
Although each pattern is helpful in certain situations, it is vital to use them with caution. It is often better to start by designing your code without using any of these patterns. They can make your code more complex and challenging to maintain. Then, refactor the code to introduce the pattern once you see the need to add one of these patterns.
However, it is important to understand the different creational design patterns and when they are appropriate to use since they can help you create more efficient and flexible code.