Suppose we have more than one classes which have a common parent class or a common implementing interface.
Now, we need to create an object of one of the classes based on some condition.
In this case, we create a method whose return type is the parent class or interface and based on the condition, we create an object of child or implementing class.
This object creation method is placed in a factory class and the client or the code that requires the object calls this method.
Benefits of this approach are obvious, as given below:
1. Object creation logic at one single place, which makes maintenance easier.
2. Loose coupling between object creation and the client.
3. Easy to implement.
Below is a definition for this pattern
The Factory design pattern is a creational design pattern that provides a way to create objects without exposing the object creation logic to the client code.
Factory design pattern example
Suppose we have an online food ordering system that provides different types of cuisines like Chinese, Indian, and Italian.
The system should provide an interface to order food from any of these cuisines, but the actual implementation of the order should be hidden from the client code.
In this example, each cuisine will be represented by a class. So, we will have ChineseCuisine
, IndianCuisine
and ItalianCuisine
classes.
Since all the classes will have same methods but different implementations, we can create a parent class or an interface for all these classes.
Let’s create a parent class named Cuisine
as shown below
public abstract class Cuisine { public void prepare(); public void cook(); public void serve(); }
Note that since all its methods will be implemented by the child classes, the methods and class must be abstract
.
Below are the classes that extend this class
ChineseCuisine.java
public class ChineseCuisine extends Cuisine { public void prepare() { System.out.println("Preparing Chinese Cuisine"); } public void cook() { System.out.println("Cooking Chinese Cuisine"); } public void serve() { System.out.println("Serving Chinese Cuisine"); } }
IndianCuisine.java
public class IndianCuisine extends Cuisine { public void prepare() { System.out.println("Preparing Indian Cuisine"); } public void cook() { System.out.println("Cooking Indian Cuisine"); } public void serve() { System.out.println("Serving Indian Cuisine"); } }
ItalianCuisine.java
public class ItalianCuisine extends Cuisine { public void prepare() { System.out.println("Preparing Italian Cuisine"); } public void cook() { System.out.println("Cooking Italian Cuisine"); } public void serve() { System.out.println("Serving Italian Cuisine"); } }
UML diagram for these classes is
Now, in order to create an object of these classes dynamically, we also need a factory class, which is given below
public class CuisineFactory { public Cuisine prepareFood(String cuisineType) { Cuisine cuisine = null; if(cuisineType.equals("Chinese")) { cuisine = new ChineseCuisine(); } else if(cuisineType.equals("Indian")) { cuisine = new IndianCuisine(); } else if(cuisineType.equals("Italian")) { cuisine = new ItalianCuisine(); } return cuisine; } }
Above factory class accepts a type parameter and based on its value, it creates the corresponding class object.
Note that the return type of this method is that of super class Cuisine
. So, factory method makes use of Polymorphism.
Below is the client code which needs an object of these classes
public class Client { public static void main(String[] args) { CuisineFactory factory = new FoodFactory(); Cuisine chinese = factory.prepareFood("Chinese"); Cuisine indian = factory.prepareFood("Indian"); Cuisine italian = factory.prepareFood("Italian"); chineseCuisine.prepare(); chinese.cook(); chinese.serve(); indian.prepare(); indian.cook(); indian.serve(); italian.prepare(); italian.cook(); italian.serve(); } }
You can see that the client has no knowledge about how and which object it is getting.
It only provides a key and get the object. Note that the reference variables of all the objects is the same but the actual object is different.
Therefore, Factory design pattern provides does not expose the object creation logic to the client code.
It also provides a single point of control for creating objects of a particular type or hierarchy.
Advantages of Factory pattern
Below are some advantages of Factory design pattern in java
1. Provides a way to create objects without exposing the object creation logic to the client code.
2. Centralizes object creation and provides a single point of control for creating objects of a specific type.
3. Enables the use of interfaces and abstractions, making the code more modular and flexible.
4. It becomes easier to introduce new object types as we only need to modify factory class and add other product types, making the code more maintainable.
5. Provides loose coupling between client code and object creation code, making it easier to test and modify.
Disadvantages of Factory pattern
Below are some disadvantages of Factory design pattern in java
1. Adds extra complexity to the code, which may not be necessary for small-scale applications.
2. Requires a separate classes for each type, which increases the code base and unit testing effort.
3. This may also lead to an increase in the number of classes, if the number of products are large.
4. Increase the overhead of the system due to the extra layers of abstraction.
That is all on Factory pattern in java. Hope the article was useful.