Factory Method solves the problem of creating product objects without specifying their concrete classes. we expose a method used to create an object without using a direct constructor. it provides an interface to create an object to a parent class while the subclasses are allowed to implement the objects. These objects are not identical but related, Factory Pattern provides a level of abstraction over the object creation process, allowing for more flexible, maintainable, and testable code. It's especially useful in situations where the exact type of the object may not be known until runtime.
Motivation
- Need for a flexible and extensible way to create an object.
- Decouple the client from the objects it needs to create.
- A class cannot anticipate the exact object it must create.
Implementation
Our example will be a phone factory that creates phones and distributes phones, Imagine creating an iPhone and distributing it, one would need a factory for this. Looking at the code block below, the iPhone factory creates an Iphone by calling createIphone and it returns an Iphone and it distributes an Iphone by calling distributeIphones.
class Iphone {
@Override
public String toString() {
return "This is an iPhone!";
}
}
class IphoneFactory {
public Iphone createIphone() {
return new Iphone();
}
public void distributeIphones() {
System.out.println("Distributing iPhones");
}
}
This code looks good and solves our problem but what if we want to create Samsung phones and distribute them then we realize that our code is tightly coupled and is not flexible enough which gives reasons to use the factory method (TODO : adds SOLID principles yarns). The code below provides a loosely coupled implementation where we can add different brands of phones with little or no hassle while maintaining flexibility and testability.
public interface PhoneFactory {
Phone createPhone();
default void distributePhones() {
System.out.println("Distributing Smart Phones");
}
}
public class IphoneFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new IPhoneSmartPhone();
}
}
public interface Phone {
public String getPhonePrice();
}
public class IPhone implements Phone {
@Override
public String getPhonePrice() {
return "iPhone Costs $1000";
}
}
We have a PhoneFactory interface that provides a method to createPhones which a concrete class can implement as seen in IphoneFactory, the distributePhones method is left as a default method because it is assumed that distribution does not change across different brands. The createPhones returns an Iphone object that also depends on the phone Interface which enforces the rule of Liskov substitution principle. Let’s add a factory for Samsung as we tried to do initially that means we will have a Samsung object that depends on the Phone interface as well as a SamsungFactory that depends on PhoneFactory and implements the factory method createPhones. This design pattern has made the creation of identical but related objects possible. We could add other brands like pixel and one plus and it would still be as easy because we are depending on abstraction rather than concrete implementation.
public class SamsungFactory implements PhoneFactory {
@Override
public Phone createPhone() {
return new SamsungSmartPhone();
}
}
public class Samsung implements Phone {
@Override
public String getPhonePrice() {
return "Samsung Costs $900";
}
}
Advantages
- Class cannot anticipate the exact object it must create.
- Class wants subclasses to specify the object it needs to create
- Class delegates responsibility to sub-classes
- Loose coupling
- testing
Disadvantages
- Complexity
Real Life Example
- Calendar.
- Numberformat.
- ResourceBundle.
- UI Libraries.
Conclusion
In Java and other object-oriented languages, the Factory Pattern is a useful tool for creating loose coupling and flexibility in object production. By addressing the requirement to decouple client code from concrete object classes, the software becomes more maintainable and adaptive. Even while it could add a little more complexity, its benefits in terms of code extensibility and maintainability frequently exceed the disadvantages, especially in complex software systems.
Top comments (0)