Sitemap

TIL #7

4 min readOct 26, 2026

--

Press enter or click to view image in full size

Factory Design Pattern

As I continue jumping between various Udemy courses, today I am back on to Design Patterns in Java.

Introduction to design patterns

The Gang of Four (GoF) design patterns are grouped into three categories:

  • Creational — includes patterns such as Factory Method, Singleton, and Prototype.
  • Structural — includes Adapter, Bridge, and Composite.
  • Behavioral — includes Iterator, Observer, and Strategy.

Why use design patterns?

Design patterns:

  • Address recurring software design problems.
  • Can help developers write code that is easier to understand and maintain.
  • Give developers a shared vocabulary. Naming a pattern can communicate a design approach without explaining every detail from scratch.

The Simple Factory

The Simple Factory pattern falls under the category of Creational.

Get Rich’s stories in your inbox

Join Medium for free to get updates from this writer.

Creational design patterns:

  • Focus on how objects are created.
  • Decouples object creation from object usage.
  • Provides flexibility in deciding which object is needed for a given use case.
  • Makes the system independent of how objects are created, composed and used.
  • Abstracts the complexity of the object request.
  • Tell the system what you need, don’t care how its done, just tell it what you want.

Intent

  • The intent with this pattern is to provide a way to create objects using a common interface without exposing creation logic.
  • Allow the actual object type to be decided at runtime.

Problem

  • The pattern aims to solve the problem of creating an instance of one of many related classes and want it to be centralised.

Solution

  • Use a factory class with a method that decides which object to create based on the input provided to it.

Example

The example provided here is based on creating various different types of notifications, SMS, Email and WhatsApp. The classes themselves are very simple and are for demo purposes only.

“The intent with this pattern is to provide a way to create objects using a common interface without exposing creation logic.”

As we have 3 different Notification types, we should have a common interface that is shared between them for notifying a user when a notification is sent:

public interface Notification {

void notifyUser();
}

Now for our concrete classes that implement this Notification Interface:

public class SmsNotification implements Notification {

@Override
public void notifyUser() {
System.out.println("SMS has been sent");
}
}
public class EmailNotification implements Notification {

@Override
public void notifyUser() {
System.out.println("Email has been sent");
}

public void sendEmail() {
System.out.println("Sending email...");
}
}
public class WhatsAppNotification implements Notification {

@Override
public void notifyUser() {
System.out.println("WhatsApp has been sent");
}
}

Use a factory class with a method that decides which object to create based on the input provided to it.

With our Interface and Notification types created, we can turn to our Notification Factory class.

This class has a single static method so that we don’t need to instantiate it in order to make a call to it.

It has one parameter of type String, which will be the type of Notification we wish to create.

It uses a switch statement to determine what type to create and then returns the desired Notification type to our caller.

public class NotificationFactory {

public static Notification createNotification(String type) {
if (type == null || type.isEmpty()) {
return null;
}

return switch (type.toLowerCase()) {
case "email" -> new EmailNotification();
case "sms" -> new SmsNotification();
case "whatsapp" -> new WhatsAppNotification();
default -> throw new IllegalArgumentException("Unknown notification type " + type);
};
}
}
Press enter or click to view image in full size
Class diagram
Class diagram

It does have a simple check to ensure the type has a value before continuing. We make the type lowercase for consistency and if the type is not 1 of the expected 3, throw an exception as in that instance the Factory class does not know what to create.

As we can see from our switch statement, depending on the type passed to the Notification Factory, we return a new instance of EmailNotification, SmSNotification, or WhatsAppNotification.

Now for testing our Notification factory I created a simple Main method that calls the factory 4x. Once for each of the 3 concrete Notification types and once with an unknown type which should throw an IllegalArgumentException.

public class MainApp {

static void main() {
// Create a WhatsAppNotification
Notification whatsAppNotification = NotificationFactory.createNotification("WhatsApp");
whatsAppNotification.notifyUser();

// Create an SMS Notification
Notification smsNotification = NotificationFactory.createNotification("SMS");
smsNotification.notifyUser();

// Create an email notification
Notification emailNotification = NotificationFactory.createNotification("Email");
emailNotification.notifyUser();

// Throw Illegal Arg Exception
try {
Notification wan = NotificationFactory.createNotification("wa");
whatsAppNotification.notifyUser();
} catch (IllegalArumentException ex) {
System.out.println(ex.getMessage());
}

}
}

The console output from running the Main class:

WhatsApp has been sent
SMS has been sent
Email has been sent
Unknown notification type wa

UML Sequence diagram showing the flow:

Press enter or click to view image in full size
UML Sequence Diagram
UML Sequence Diagram

--

--