π Factory Design Pattern in Java
The Factory Design Pattern is a creational design pattern used to create objects without exposing the creation logic to the client.
Instead of using new
keyword directly, we delegate the object creation to a factory method.
π― Real-Life Analogy
π§ Imagine ordering a drink at a juice shop.
You don't care how the juice is made β you just say "Give me an Orange Juice", and the shop handles the rest.
Similarly, with the Factory Pattern, the factory class creates the object based on your input.
π§ When to Use It?
- When the object creation logic is complex or depends on conditions.
- When you want to centralize creation logic.
- When you need loose coupling between classes.
π₯ Basic Example β Shape Factory
πΈ Step 1: Create a common interface
interface Shape {
void draw();
}
πΈ Step 2: Implement different shapes
class Circle implements Shape {
public void draw() {
System.out.println("Drawing a Circle");
}
}
class Square implements Shape {
public void draw() {
System.out.println("Drawing a Square");
}
}
πΈ Step 3: Create a Factory class
class ShapeFactory {
public Shape getShape(String shapeType) {
if (shapeType == null) return null;
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}
πΈ Step 4: Use Factory in Main Class
public class Main {
public static void main(String[] args) {
ShapeFactory factory = new ShapeFactory();
Shape shape1 = factory.getShape("CIRCLE");
shape1.draw();
Shape shape2 = factory.getShape("SQUARE");
shape2.draw();
}
}
β Output
Drawing a Circle
Drawing a Square
π Key Concepts
| Concept | Description | | --------------------- | ------------------------------------------------- | | Loose Coupling | Client doesnβt care how objects are created | | Reusability | Easy to manage and extend object creation | | Encapsulation | Hides object instantiation logic | | Open/Closed Principle | Easy to add new shapes without modifying old code |
π§ Real-World Use Case: Notification Service
Suppose your app supports notifications via Email and SMS. The client should just say βSend Notificationβ β the factory decides how.
πΈ Step 1: Notification Interface
interface Notification {
void notifyUser();
}
πΈ Step 2: Implementations
class EmailNotification implements Notification {
public void notifyUser() {
System.out.println("Sending Email Notification");
}
}
class SMSNotification implements Notification {
public void notifyUser() {
System.out.println("Sending SMS Notification");
}
}
πΈ Step 3: Factory Class
class NotificationFactory {
public Notification createNotification(String type) {
if (type == null || type.isEmpty()) return null;
if (type.equalsIgnoreCase("EMAIL")) {
return new EmailNotification();
} else if (type.equalsIgnoreCase("SMS")) {
return new SMSNotification();
}
return null;
}
}
πΈ Step 4: Main Class
public class NotificationService {
public static void main(String[] args) {
NotificationFactory factory = new NotificationFactory();
Notification email = factory.createNotification("EMAIL");
email.notifyUser();
Notification sms = factory.createNotification("SMS");
sms.notifyUser();
}
}
β Output
Sending Email Notification
Sending SMS Notification
π« Anti-Patterns to Avoid
- β Huge
if-else
chains in factory β use enum or config to clean it later. - β Mixing business logic inside factory β keep factory focused on object creation only.
π§ Interview Q&A
Q: What pattern category does Factory belong to? A: Creational
Q: What's the difference between Factory and Abstract Factory? A:
- Factory β returns one family/type of object.
- Abstract Factory β returns related objects from multiple factories.
Q: Why not just use new
?
A: Because new
tightly couples the client with the implementation. Factory gives you flexibility and control.
π Summary
- β Factory Pattern helps in creating objects in a clean and controlled way.
- π§± Promotes loose coupling, reusability, and maintainability.
- π¦ Useful when object creation is conditional, dynamic, or complex.