Factory Design pattern is one of the most popular creational design pattern. Factory pattern is used to create different types of objects without specifying the exact class of object that will be created. Sometimes creating an object requires complex processes not appropriate to include within client object.
Factory class abstract the complex logic of object creation from client and and provides a common interface for client to refers to the any newly created object. In Factory method, subclasses are responsible to create the object of the class.
In this tutorial, we will explore the Factory Design Pattern in Java. We'll discuss its structure, benefits, and provide example of how to implement the pattern.
Structure of the Factory Design Pattern
- Product Interface/Abstract Class : This is an interface or abstract class that defines the interface for the objects to be created.
- Concrete Products : These are the classes that implement the Product interface and represent the objects to be created.
- Creator Interface/Abstract Class : This is an interface or abstract class that declares the factory method, which returns an object of type Product.
- Concrete Creators : These are the classes that implement the Creator interface and override the factory method to create specific instances of the Product.
Advantages of Factory Pattern
- Encapsulation : The creation of objects is encapsulated within the factory method, providing a clear separation of concerns. Clients using the factory method don't need to know the details of object creation; they simply request an object from the factory.
- Flexibility : This approach facilitates seamless adjustment of the object types crafted by the factory method. Should a client seek a different type of object, a new concrete creator can be introduced without necessitating alterations to existing client instructions.
- Code Reusability : Centralizing object creation within the factory method fosters the reuse of code. The same factory method can be applied across varied sections of your application or even extend its utility to diverse projects.
- Simplified Maintenance : The Factory Pattern Approach contributes to enhanced maintainability. When modifications to object creation logic are essential, the focus remains on altering the factory method or introducing a new artisanal creator, sparing extensive modifications to requester code.
Implementation of Factory Design Pattern
We will create an interface called 'Bird' containing 'fly()' method. Then we will define concrete classes "Owl", "Eagle" and "Sparrow" implementing Bird interface.
public interface Bird { void fly(); }Owl.java
public class Owl implements Bird { @Override public void fly() { System.out.println("Owl is Flying"); } }Eagle.java
public class Eagle implements Bird { @Override public void fly() { System.out.println("Eagle is Flying"); } }Sparrow.java
public class Sparrow implements Bird { @Override public void fly() { System.out.println("Sparrow is Flying"); } }
Now, We will create a factory class BirdFactory.java to create objects of specific bird types based on given input parameter.
BirdFactory.javapublic class BirdFactory { //getBird is a factory method to get various bird objects public Bird getBird(String birdSpecies){ if(birdSpecies == null){ return null; } if(birdSpecies.equalsIgnoreCase("EAGLE")){ return new Eagle(); } else if(birdSpecies.equalsIgnoreCase("OWL")){ return new Owl(); } else if(birdSpecies.equalsIgnoreCase("SPARROW")){ return new Sparrow(); } else { return null; } } }
We are creating a BirdSanctuary.java to demo the working of factory class. It will create an instance of factory class and use it to create various bird objects.
BirdSanctuary.javapublic class BirdSanctuary { public static void main(String[] args) { // Create a factoru class instance BirdFactory factory = new BirdFactory(); //get Owl object typecasted to Bird Interface. Bird owl = factory.getBird("OWL"); //get Sparrow object typecasted to Bird Interface. Bird sparrow = factory.getBird("SPARROW"); //get EAGLE object typecasted to Bird Interface. Bird eagle = factory.getBird("EAGLE"); // Call fly function of all birds owl.fly(); sparrow.fly(); eagle.fly(); } }
Output
Owl is Flying Sparrow is Flying Eagle is Flying
- Clients create objects using factory instead of directly creating it using new operator. It calls factory object and specify what type of object is needed.
- Factory pattern creates various objects without exposing the complex logic of object creation.
- The factory method returns newly created object as requested by client after type casting it to a common interface.
- Client interact with object through interface, without being aware of the type of concrete class.
Best Practices of Factory Pattern
- Abstraction through Interfaces : Emphasize the use of interfaces or abstract classes for both the product and author. This abstraction provides flexibility, allowing the grouping of related entities.
- Use of Dependency Inversion Principle : To use the Dependency Inversion Principle, rely on concepts instead of specific classes. This makes your design more adaptable and makes it easier to add new types of goods or makers.
- Creator Should Not Be Instantiated Directly : Avoid the direct instantiation of actual creator classes. Clients should not create instances directly; instead, they should utilize the creator method or an abstract class to obtain crafted items. This makes sure that the process of making something stays inside the factory way.
- Single Responsibility Principle : There should be only one duty for each class, such as a product or an author. Products should focus on delivering their own features, and makers should be in charge of making cases of products. This aligns with the Single Responsibility Principle.
- Flexibility and Extensibility : Design the factory pattern approach with an eye toward future extensibility. Adding products or creators should be a straightforward process without requiring modifications to existing client instructions, aligning with the open/closed principle.
- Consideration of Static Crafting Methods : While the examples have used non-static factory methods, it's essential to note that factory methods can also be static. However, static methods lack flexibility as they cannot be altered in subclasses. Choose the method that best fits your design requirements.
- Naming Conventions : Employ clear and consistent naming conventions for interfaces, abstract classes, concrete products, and concrete creators. This promotes code readability and facilitates understanding for other developers interacting with your code.
Conclusion
The Factory Design Pattern is a powerful creational pattern that promotes flexibility, encapsulation, and code reusability. It is particularly useful in scenarios where object creation logic may vary or where clients need to interact with different types of objects without knowing their concrete implementations.
By understanding the structure and benefits of the Factory Design Pattern, you can apply it to create modular and extensible systems. In the examples provided, we explored how to use the Factory Design Pattern to create different types of vehicles and loggers. The pattern can be adapted to various situations, making it a valuable tool in the software design toolbox.
Related Topics
Abstract Factory Design Pattern |
Builder Design Pattern |
Singleton Design Pattern |
Command Design Pattern |
Strategy Design Pattern |
State Design Pattern |
Flyweight Design Pattern |