Table of Contents
ToggleThe Factory Design Pattern is one of the most commonly used design patterns in object-oriented software development. It falls under the category of creational patterns, as it deals with object creation mechanisms.
The pattern aims to create objects without specifying the exact class of object that will be created. This is achieved by defining an interface for creating an object, but letting subclasses decide which class to instantiate. The Factory Method lets a class defer instantiation to subclasses.
What is factory design pattern with real time example?
In essence, the Factory Design Pattern suggests defining an interface or abstract class for creating an object but allowing the subclasses to choose the class to be instantiated. This pattern is particularly useful when there is a need to manage and maintain a large number of derived classes derived from a common interface or base class. Let’s understand via real time example.
For Example
Imagine you own a toy factory that makes different types of toys: cars, planes, and dolls. You have a general plan (interface or abstract class) for making a toy, which includes steps like designing, assembling, and painting. However, the specifics of creating each type of toy vary significantly.
In this scenario, the Factory Design Pattern is like having a general manager (the interface or abstract class) who knows the steps to make a toy but not the specifics of each type. When it’s time to make a new toy, the general manager decides which specific toy factory (subclass) to use based on the toy type requested.
- If a customer wants a car, the general manager directs the request to the car factory (subclass) which knows how to assemble cars specifically.
- If the order is for a plane, the plane factory (another subclass) takes over, using its expertise to build planes.
- For dolls, the request goes to the doll factory (yet another subclass) that specializes in creating dolls.
This approach is helpful when managing many types of toys (or derived classes) that share a common creation process (interface or base class) but have their own specific manufacturing details.
Why Do We Need the Factory Design Pattern?
The need for the Factory Design Pattern arises in scenarios where a system should be independent of how its objects are created, composed, and represented. It provides a way to encapsulate object creation so that the type of objects used in a system can be specified at runtime.
Let’s understand this via code example.
Imagine you are developing an application that requires different types of notification services: email, SMS, and push notifications. Initially, you might start with a straightforward approach like this:
// Straightforward Approach
class NotificationService {
void sendNotification(String type, String message) {
if (type.equals("Email")) {
// Code to send email
System.out.println("Sending Email: " + message);
} else if (type.equals("SMS")) {
// Code to send SMS
System.out.println("Sending SMS: " + message);
} else if (type.equals("Push")) {
// Code to send Push Notification
System.out.println("Sending Push Notification: " + message);
}
}
}
There are few issues with this code.
- Violation of Single Responsibility Principle (SRP): The
NotificationService
class is responsible for determining the type of notification to send and sending the notification itself. This violates the SRP, as a class should have only one reason to change. If there are changes in the way notifications are sent or in the types of notifications, this class will need modification. - Lack of Extensibility: Adding a new type of notification (e.g., “Fax”, “Pager”, etc.) would require modifying the
sendNotification
method, which violates the Open/Closed Principle. Every time you want to add a new notification type, you’d have to modify this class. - Code Duplication: The code for sending each type of notification is embedded within the
sendNotification
method. This violates the DRY (Don’t Repeat Yourself) principle, as the same code for sending notifications is repeated for each type.
Solving the Issue with the Factory Design Pattern
The Factory Design Pattern can address this problem by encapsulating the creation logic for different notification types, thus decoupling the client code from the concrete classes.
Let’s look how to solve the above problem with factory design pattern.
How do you implement a factory design pattern?
Implementing the Factory Design Pattern involves creating a factory class that is responsible for creating and returning instances of classes based on the provided criteria.
Components of the Factory Design Pattern
- Product Interface: This defines the contract for the products created by the factory.
- Concrete Products: These are the specific implementations of the product interface.
- Creator (Factory) Interface: An interface that declares the factory method, which returns an object of the product interface.
- Concrete Creator: Implements the factory method to create and return concrete products.
Step-by-Step Implementation
Let’s see how to implement these components to solve above problem.
- Define Product Interface: We will begin by defining interface for different type of notification service which each notification service will implement.
interface Notification {
void send(String message);
}
- Implement Concrete Products: Implement each notification service in our case Email, SMS etc which will implement Notification interface.
class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Sending Email: " + message);
}
}
class SMSNotification implements Notification {
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}
class PushNotification implements Notification {
public void send(String message) {
System.out.println("Sending Push Notification: " + message);
}
}
- Define Factory Interface (Optional in some cases):
In simple implementations, you might directly implement a factory class without needing an interface.
- Implement Concrete Factory: Notification Factory which will decide which object to return based on type.
class NotificationFactory {
public static Notification createNotification(String type) {
switch (type) {
case "Email":
return new EmailNotification();
case "SMS":
return new SMSNotification();
case "Push":
return new PushNotification();
default:
throw new IllegalArgumentException("Unknown notification type");
}
}
}
- Usage: Client code will call notification factory and get object of type Notification. Now the object creation is isolated from client code.
public class Main {
public static void main(String[] args) {
Notification notification = NotificationFactory.createNotification("Email");
notification.send("Hello, World!");
}
}
By using the Factory Design Pattern:
- Single Responsibility Principle: Each class (EmailNotification, SMSNotification, PushNotification) is responsible for sending a specific type of notification. The creation of these objects is delegated to the
NotificationFactory
, separating the concerns of creation and sending. - Extensibility: Adding a new type of notification is as simple as creating a new implementation of the
Notification
interface and updating thecreateNotification
method in theNotificationFactory
class. No modifications to existing client code are necessary. - Code Duplication: Each notification type is encapsulated within its own class, eliminating code duplication.
Complete Java Code
// Notification interface
interface Notification {
void send(String message);
}
// Concrete implementation for Email notification
class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Sending Email: " + message);
}
}
// Concrete implementation for SMS notification
class SMSNotification implements Notification {
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}
// Concrete implementation for Push notification
class PushNotification implements Notification {
public void send(String message) {
System.out.println("Sending Push Notification: " + message);
}
}
// Factory class for creating instances of different notification types
class NotificationFactory {
public static Notification createNotification(String type) {
switch (type) {
case "Email":
return new EmailNotification();
case "SMS":
return new SMSNotification();
case "Push":
return new PushNotification();
default:
throw new IllegalArgumentException("Unknown notification type");
}
}
}
// Main class
public class Main {
public static void main(String[] args) {
// Create an Email notification
Notification notification = NotificationFactory.createNotification("Email");
notification.send("Hello, World!");
}
}
Common Usage in Applications
The Factory Design Pattern is widely used in software development. Common applications include:
- UI libraries and frameworks where different styles of elements are needed depending on the environment.
- In API libraries where the implementation might change based on the system configuration or usage context.
- Managing resource-intensive objects whose instantiation process should be controlled or optimized.
- LogFactory where we need to manage the creation of different types of loggers (such as file loggers, database loggers, or console loggers) based on the runtime environment or a configuration setting.
- DataSourceFactory where we need to create connections to different types of data sources (such as SQL databases, NoSQL databases, or XML files) based on application requirements.
Identifying Where to Apply Factory Design Pattern
So, now important question arises i.e. how to Identify scenarios for the Factory Design Pattern ? . USe Factory Pattern in situations where:
- Complexity in Object Creation: When object creation involves more than just instantiation and includes setting up state, dependencies, or configuration.
- Need for Flexibility: When your application needs to introduce new types of objects dynamically without changing existing code.
- Decoupling: When you want to reduce dependencies between your application’s code and the concrete classes you use.
- Consistency: When you have a set of related or dependent objects that should always be used together.
- Control Over Instantiation: When you need to control the instantiation process of an object, such as using pooling or managing limited resources.
By recognizing these scenarios in your application development, you can effectively apply the Factory Design Pattern to improve flexibility, maintainability, and scalability of your software design.
Benefits and Drawbacks Of Factory Design Pattern
Let’s see pros and cons of factory design pattern.
Benefits Of Factory Design Pattern
- Flexibility: Allows for objects to be created at runtime based on the required criteria.
- Decoupling: The client code is decoupled from the concrete classes, adhering to the principle of programming to interfaces, not implementations.
- Extensibility: Adding new types of products without disturbing existing client code.
Drawbacks Of Factory Design Pattern
- Complexity: Can introduce additional complexity into the code, especially if overused for scenarios that do not require such flexibility.
- Code Maintenance: Might increase the number of classes and interfaces, making the system harder to understand for new developers.
Key TakeAways
- Strings in C are arrays of characters terminated by a null character ‘\0’. They are stored in char arrays and can be manipulated using various string functions.
- Strings can be declared by specifying a char array of fixed size, without size (allowing automatic size calculation), or assigned character by character. Initialization can be done using string literals or individual character assignments.
- The difference between character arrays and string literals is that character arrays are modifiable, occupy memory dynamically, and need explicit initialization, while string literals are stored in read-only memory, have fixed sizes, and initialize automatically.
- Passing strings to functions can be done by passing the character array. The array contains the characters of the string which gets passed to the function through this mechanism.
Similar Posts
How Factory Design Pattern Is Used in Spring Boot?
How to Apply Factory Design Pattern for Payment System
Can We Use Factory Design Pattern in Dependency Injection?
What Is the Difference Between Factory and Abstract Factory Design Patterns?
When to Use Factory Design Pattern in Java?
FAQ
What is the main goal of the factory design pattern?
The main goal of the factory design pattern is to provide an interface for creating objects in a superclass, but allow subclasses to alter the type of objects that will be created. It promotes loose coupling by abstracting the object creation process from the client code.
What is factory design pattern with real time example?
A real-time example of the factory design pattern could be a software application that produces different types of documents, such as reports, spreadsheets, and presentations. Instead of having the client code directly instantiate each type of document (e.g., Report, Spreadsheet, Presentation), a DocumentFactory can be used. The DocumentFactory provides methods for creating different types of documents based on user input or other factors. This way, the client code only interacts with the factory to obtain instances of documents, without being concerned about their specific implementation details.
What are the types of factory pattern?
There are several variations of the factory pattern, including:
- Simple Factory: This is the most basic form of factory pattern where a factory class has methods for creating objects without exposing the instantiation logic to the client.
- Factory Method: In this pattern, a superclass provides an interface for creating objects, but allows subclasses to override the instantiation process to provide different implementations of the created objects.
- Abstract Factory: This pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. It defines a set of methods, each of which returns a different abstract product.
What is the benefit of factory pattern?
The benefits of using the factory pattern include:
- Encapsulation: It encapsulates the object creation process, hiding the implementation details of object creation from the client code.
- Flexibility: It allows for easy extension and modification of the object creation process, enabling the addition of new types of objects without modifying existing client code.
- Promotes Loose Coupling: It promotes loose coupling between the client code and the created objects, as the client code only interacts with the factory interface, not with the concrete classes directly.
- Centralized Control: It provides a centralized place (the factory) to manage the creation of objects, making it easier to maintain and refactor the code.