Last Updated on September 24, 2023 by KnownSense
The Factory Method is a design pattern that provides a way to create objects without specifying their exact classes. It lets you delegate the responsibility of creating objects to subclasses, allowing for flexible and adaptable object creation.
Imagine you’re developing an application for managing a furniture business. In the initial version of your app, it’s designed to handle only chairs, and a large portion of your code is within the Chair class.
Over time, your app gains popularity, and now you’re getting requests from companies dealing with tables, sofas, and more, asking to integrate their products into your app.
Sounds like a great opportunity, doesn’t it? But what about your code? Right now, most of it is tied to the Chair class. Adding support for tables and sofas would mean tinkering with the entire codebase. And if later you decide to expand further and include other types of furniture, you’d likely have to go through the same ordeal again.
This could lead to messy code filled with conditional statements that determine the app’s behavior based on the type of furniture objects. Employing the Factory Method can offer a solution to address this challenge.
Benefits
- Flexibility: Enables the addition of new object types or variations without modifying existing code.
- Open-Closed Principle: Supports the principle of extending system functionality without changing its core code.
- Code Organization: Centralizes object creation logic, leading to cleaner and more organized code.
- Code Reusability: Allows the same creation mechanism to be used across different parts of the application.
- Maintenance: Facilitates easier maintenance as changes to object creation logic are localized to the factory classes.
- Decoupling: Decouples client code from the specific classes of objects it creates, reducing dependencies.
- Testing: Simplifies unit testing by allowing the isolation of object creation in factory classes.
- Polymorphism: Promotes the use of polymorphism, as clients interact with objects through their common interface.
- Scalability: Scales well as new object types can be integrated seamlessly, promoting system growth.
- Design Consistency: Enforces a consistent approach to object creation throughout the application, enhancing design integrity.
UML for Factory Method
Implementation
In this implementation, we are solving the issue discussed above for furniture business.
Step1: Create a Interface Furniture with method deliver
public interface Furniture {
public void deliver();
}
Step2: Create concrete classes for different furnitures – Chair.java, Sofa.java, Table.java
public class Chair implements Furniture {
@Override
public void deliver() {
System.out.println("Deliver of Chair is successful");
}
}
public class Sofa implements Furniture {
@Override
public void deliver() {
System.out.println("Deliver of Sofa is successful");
}
}
public class Table implements Furniture {
@Override
public void deliver() {
System.out.println("Deliver of Table is successful");
}
}
Step3: Create a Factory to generate object of concrete class based on given information.
public class FurnitureFactory {
public Furniture getFur(String type){
if(type.equalsIgnoreCase("SOFA"))
return new Sofa();
else if (type.equalsIgnoreCase("CHAIR"))
return new Chair();
else
return new Table();
}
}
Step4: In mentod use the Factory to get object of concrete class.
public class factoryDesignpattern {
public static void main(String args[]){
FurnitureFactory furnitureFactory = new FurnitureFactory();
furnitureFactory.getFur("CHAIR").deliver();
furnitureFactory.getFur("SOFA").deliver();
furnitureFactory.getFur("TABLE").deliver();
furnitureFactory.getFur("CHAIR").deliver();
}
}
OUTPUT:
Deliver of Chair is successful
Deliver of Sofa is successful
Deliver of Table is successful
Deliver of Chair is successful
Conclusion
In conclusion, the Factory Method pattern proves invaluable in software design by promoting code flexibility, scalability, and maintainability. By encapsulating object creation within dedicated factory classes, it mitigates code coupling and empowers developers to introduce new product variants without altering existing code. This pattern aligns with the open-closed principle and encourages modular design, making it an essential tool for building adaptable and extensible applications.