- Factory Method Pattern
- Introduction
- Simple Implementation
- Simple Factory
- Structure
- Supporting multiple manufacturers
- Multiple Simple Factories
- Factory Method
- Structure
- Participants
- Other Forms of Factory Method
- Factory Method – Pros
- Factory Method – Cons
- Design principles used
- Conclusion
- References and Resources
- Share This Post Share this content
- Factory method design pattern in Java
Factory Method Pattern
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
In this post we will have a look at the Simple Factory that will lead us to the Factory Method Design Pattern. The extension of the Factory Method will lead us to the Abstract Factory Pattern which we will see in the later posts.
Introduction
The TelevisionManufacturer class is responsible for creating Televisions. There are different kinds of television based on the type like LED, LCD and Plasma. Here’s a first attempt at the implementation.
Simple Implementation
package com.javadevcentral.pattern.factory.simple; import com.javadevcentral.pattern.factory.TelevisionType; import com.javadevcentral.pattern.factory.televisions.LCDTelevision; import com.javadevcentral.pattern.factory.televisions.LEDTelevision; import com.javadevcentral.pattern.factory.televisions.PlasmaTelevision; import com.javadevcentral.pattern.factory.televisions.Television; public class TelevisionManufacturer < public Television manufactureTelevision(TelevisionType televisionType) < Television television; switch (televisionType) < case LED: television = new LEDTelevision(); break; case LCD: television = new LCDTelevision(); break; case PLASMA: television = new PlasmaTelevision(); break; default: throw new RuntimeException("Unknown Television type " + televisionType); >television.checkQuality(); television.box(); return television; > >
package com.javadevcentral.pattern.factory; public enum TelevisionType
Let Television be a simple class with a set of properties and let LEDTelevision, LCDTelevision and PlasmaTelevision inherit the Television class.
After creating a television, the manufacturer does some operations like QA check and finally boxes it. At runtime, it creates a Television object based on the type of television that is needed. There are several problems with this:
- When we have to add (or remove) a new Television type, this class has to be changed. This clearly violates the Open Closed Principle (OCP) principle which states that classes must be open for extension but closed for modifications.
- Often, creating a Television object for a given type might be needed in several other places too. Reuse of this logic is not possible with this structure or implementation.
- Creating concrete classes in this class ties this class with the implementation details.
To solve this, we look at the design principle ‘Encapsulate what varies’. It says – identify the aspects that vary and separate them from what stays the same (We applied this in the Strategy Pattern too).
Simple Factory
The part of the code that creates concrete Television objects is the part that varies. So, we encapsulate it into a new object – the SimpleTelevisionFactory . Whenever we need a new Television (in the TelevisionManufacturer ), we just call the createTelevision method on the TelevisionFactory.
package com.javadevcentral.pattern.factory.simple; import com.javadevcentral.pattern.factory.TelevisionType; import com.javadevcentral.pattern.factory.televisions.LCDTelevision; import com.javadevcentral.pattern.factory.televisions.LEDTelevision; import com.javadevcentral.pattern.factory.televisions.PlasmaTelevision; import com.javadevcentral.pattern.factory.televisions.Television; public class SimpleTelevisionFactory < public Television createTelevision(TelevisionType televisionType) < Television television; switch (televisionType) < case LED: television = new LEDTelevision(); break; case LCD: television = new LCDTelevision(); break; case PLASMA: television = new PlasmaTelevision(); break; default: throw new RuntimeException("Unknown Television type " + televisionType); >return television; > >
In this way, our manufacturer client code is not tied to any concrete Television class (it depends on the Television abstraction). This also enables any other code to reuse the TelevisionFactory to create Television objects. This also makes maintenance easy as there is just one place to change (the TelevisionFactory) when the type of televisions to support changes in the future.
The TelevisionManufacturer code now becomes,
package com.javadevcentral.pattern.factory.simple; import com.javadevcentral.pattern.factory.TelevisionType; import com.javadevcentral.pattern.factory.televisions.Television; public class TelevisionManufacturer < private SimpleTelevisionFactory simpleTelevisionFactory; public TelevisionManufacturer(SimpleTelevisionFactory simpleTelevisionFactory) < this.simpleTelevisionFactory = simpleTelevisionFactory; >public Television manufactureTelevision(TelevisionType televisionType) < Television television = simpleTelevisionFactory.createTelevision(televisionType); television.checkQuality(); television.box(); return television; >>
We pass the TelevisionManufacturer a reference to the SimpleTelevisionFactory which it uses to create Televisions.
What we have seen above is an implementation of the ‘Simple Factory’. It is not a design pattern but it is a programming idiom used often. Do not confuse Simple Factory with the Factory Method.
Structure
Supporting multiple manufacturers
Now, we have a Television Manufacturer class that can manufacture top-notch televisions. It is not coupled to any kind of Television object. Now, we need to support different manufacturers for different brands of TVs say, Samsung, LG, Philips, etc. Each manufacturer builds its own classes of Televisions (Samsung LED, Samsung LCD, Philips LEG, Philips LCD etc.)
Multiple Simple Factories
One option is to extend the idea of Simple Factory by replacing the SimpleTelevisionFactory with different factories for each of the manufacturers. Then we can pass the appropriate reference to a factory to our main TelevisionManufacturer
SamsungTelevisionFactory samsungTelevisionFactory = new SamsungTelevisionFactory(); TelevisionManufacturer televisionManufacturer = new TelevisionManufacturer(samsungTelevisionFactory); //Creates Samsung LED TV televisionManufacturer.manufactureTelevision(TelevisionType.LED); PhilipsTelevisionFactory philipsTelevisionFactory = new PhilipsTelevisionFactory(); TelevisionManufacturer televisionManufacturer = new TelevisionManufacturer(philipsTelevisionFactory); //Creates Philips LCD TV televisionManufacturer.manufactureTelevision(TelevisionType.LCD);
This would work fine. But what if each manufacturer did the QA check or the boxing differently? So, we need a framework that ties the TV manufacturer and the manufacturing together.
Factory Method
We will bring the createTelevision method into the TelevisionManufacturer class but as an abstract method. We will have subclasses (of TelevisionManufacturer) for the different manufacturers (SamsungManufacturer, PhilipsManufacturer etc). They will provide an implementation for the createTelevision and they will fully own the Television creation logic. Since the createTelevision method is now abstract the TelevisionManufacturer class will also be marked abstract.
package com.javadevcentral.pattern.factory.method; import com.javadevcentral.pattern.factory.TelevisionType; import com.javadevcentral.pattern.factory.televisions.Television; public abstract class TelevisionManufacturer < public Television manufactureTelevision(TelevisionType televisionType) < Television television = createTelevision(televisionType); television.checkQuality(); television.box(); return television; >protected abstract Television createTelevision(TelevisionType televisionType); >
From the TelevisionManufacturer standpoint, it just calls the createTelevision abstract method, and it gets back a Television object. It does not know what kind of television is being returned. It is solely decided by the choice of the subclass (manufacturer) we choose to manufacture from.
Let us take a look at the individual manufacturers.
package com.javadevcentral.pattern.factory.method; import com.javadevcentral.pattern.factory.TelevisionType; import com.javadevcentral.pattern.factory.televisions.SamsungLCDTelevision; import com.javadevcentral.pattern.factory.televisions.SamsungLEDTelevision; import com.javadevcentral.pattern.factory.televisions.SamsungPlasmaTelevision; import com.javadevcentral.pattern.factory.televisions.Television; public class SamsungTelevisionManufacturer extends TelevisionManufacturer < @Override protected Television createTelevision(TelevisionType televisionType) < Television television; switch (televisionType) < case LED: television = new SamsungLEDTelevision(); break; case LCD: television = new SamsungLCDTelevision(); break; case PLASMA: television = new SamsungPlasmaTelevision(); break; default: throw new RuntimeException("Unknown Television type " + televisionType); >return television; > >
Similarly a PhilipsTelevisionManufacturer will look the same way except that it will return PhilipsLEDTelevision , PhilipsLCDTelevision and PhilipsPlasmaTelevision .
The abstract method on the TelevisionManufacturer is called the factory method. It takes care of object creation and encapsulates it in the subclass.
For the sake of completeness, a Television class described so far might look like this (The exact details are not important here).
package com.javadevcentral.pattern.factory.televisions; import java.util.List; public class Television < private String model; private int warrantyInYears; private ListspecialFeatures; public void checkQuality() < System.out.println("Checking the Quality of the TV"); >public void box() < System.out.println("Packing the TV in a box"); >>
Structure
Participants
Product (Television)
ConcreteProduct (SamsungLEDDocument)
Creator (TelevisionManufacturer)
- Declares the factory method, which returns an object of type Product. It calls the factory method to create a Product object.
ConcreteCreator (SamsungTelevisionManufacturer)
Other Forms of Factory Method
Default implementation of the factory method : In some cases, the Creator class can provide a default implementation of the factory method. In such cases, the Creator class can be marked non-abstract.
Non-parameterized factory method : The version of the factory method that we saw involves sending a parameter to the factory method using which the subclasses made some decision. This is called a parameterized factory method. There is also another version that does not have any parameters.
Factory Method – Pros
- Less coupling: No need to couple the creator class with specific concrete (Product) classes. It does this by moving the concrete Product object creation to the subclasses.
- SRP and OCP: With above, we also adhere to the Single Responsibility Principle (SRP) and the Open Closed Principle (OCP) .
- Provides a hook for subclasses: When the factory method provides a default implementation, the factory method effectively becomes a hook. The subclasses can override this method to return a more specific object when the default implementation does not apply. For others, the default implementation would be sufficient.
- Provides a framework: It allows us to build a framework involving the object creation through subclass. Usually the factory method is called from one of the methods (sometimes marked as final) in the abstract creator. Once the object (product) is created and returned, it does some operations on it. Thus, this other method provides a framework whereas the subclass decide what product object to create.
Factory Method – Cons
- Need to subclass: We have to create a subclass to implement the abstract factory method just to create a product.
Design principles used
- Program to an interface, not implementations
- Encapsulate what varies – Identify the aspects of your application that vary and separate them from what stays the same.
Conclusion
The Factory Method allows us to encapsulate the creation of concrete objects. This leads to less coupling, code reuse, and easier maintenance. The Abstract creator has an (abstract) factory method that acts as a hook for the subclasses to create concrete product objects. The Abstract Creator does know about the concrete products that are created. It is decided by our choice of the subclass to be used. Usually the other methods in the Abstract Creator operate on the product object returned by the factory method.
References and Resources
- Head First Design Patterns: A Brain-Friendly Guide by Eric Freeman and Elisabeth Robson.
- Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.
- Why is the factory method design pattern more useful than having classes and calling them individually?
Share This Post Share this content
Factory method design pattern in Java
It is a creational design pattern that talks about the creation of an object. The factory design pattern says that define an interface ( A java interface or an abstract class) for creating object and let the subclasses decide which class to instantiate. The factory method in the interface lets a class defers the instantiation to one or more concrete subclasses. Since these design patterns talk about the instantiation of an object and so it comes under the category of creational design pattern. If we notice the name Factory method, that means there is a method which is a factory, and in general, factories are involved with creational stuff and here with this, an object is being created. It is one of the best ways to create an object where object creation logic is hidden from the client. Now Let’s look at the implementation.
Implementation:
- Define a factory method inside an interface.
- Let the subclass implements the above factory method and decides which object to create.
- In Java, constructors are not polymorphic, but by allowing subclass to create an object, we are adding polymorphic behavior to the instantiation. In short, we are trying to achieve Pseudo polymorphism by letting the subclass to decide what to create, and so this Factory method is also called a virtual constructor.
Let us try to implement it with a real-time problem and some coding exercises.
Problem Statement: Consider we want to implement a notification service through email, SMS, and push notifications. Let’s try to implement this with the help of the factory method design pattern. First, we will design a UML class diagram for this.
In the above class diagram, we have an interface called Notification, and three concrete classes are implementing the Notification interface. A factory class NotificationFactory is created to get a Notification object. Let’s jump into the coding now.
Create Notification interface