Factory pattern is a design pattern that allows you to create objects without exposing the instantiation logic to the client.
It's a way to delegate the instantiation of an object to a factory class without the client having to decide the concrete class to instantiate.
Let's see some terminology:
- Client - The class that needs the object.
- Factory - The class that creates the object.
- Deciding parameters - The parameters that the factory class uses to decide which concrete class to instantiate.
- The Abstraction - When the client gets an object, it wants it to do something. So it needs to know which types of objects it needs.
A real world analogy
Let's think about a real world example of factory pattern
- Let's say you order a Car through the Uber app.
- You order a car for a particular location and maybe a particular time.
- However, you don't know which car will be provided to you until the order is complete.
- Once the order is complete, you can get the car details.
Let's compare this to our factory terminology:
- You are the client.
- Uber is the factory. It will find a car for you. You don't need to know how it does that.
- Location and time are the deciding parameters.
- The car is the abstraction. You are certain that you need a car and specifically will be provided a car.
Now let's implement this in Java.
The Abstraction
First, lets create a Car interface and provide some implementations for it.
// Car interface
public interface Car {
public void drive();
}
// its implementations
public class Sedan implements Car {
public void drive() {
System.out.println("Driving a Sedan");
}
}
public class SUV implements Car {
public void drive() {
System.out.println("Driving a SUV");
}
}
Car could also be an abstract class in case you want to provide some common functionality to all the cars. It could also have more methods. Leaving the extra code out for simplicity.
The Factory
Now, let's create a factory class.
public class CarFactory {
public static Car getCar(String location, String time) {
if (location.equals("LA") && time.equals("morning")) {
return new Sedan();
} else if (location.equals("LA") && time.equals("evening")) {
return new SUV();
} else if (location.equals("NY") && time.equals("morning")) {
return new SUV();
} else if (location.equals("NY") && time.equals("evening")) {
return new Sedan();
} else {
return null;
}
}
}
Please bear with my Car choosing logic. I do not work for Uber. (yet?)
Location and time are the deciding parameters here. There could be multiple ways to write a factory.
Two other common ways are:
- Using a switch case
- Using a map of strings to objects.
We generally choose these two when there is only one deciding parameter.
The map way can help further in case you want to avoid creating redundant objects every time.
The Client
Now, let's create a client class.
public class Client {
public static void main(String[] args) {
Car car = CarFactory.getCar("LA", "morning");
if (car != null) {
car.drive();
} else {
System.out.println("Sorry, no car available");
}
}
}
Running this code will print out:
Driving a Sedan
Advantages of using Factory Pattern
There are many advantages of using factory pattern.
- Separation of concerns (loose coupling) - The client doesn't have to know how the factory class works. The client or the factory class don't have to know how the concrete implementation of the Car class work.
- Easy to extend - You can add more cars to the factory without having to change the client code.
- Easy to test - You can test the client code without having to change the factory code. You can mock the factory class to return any Car object you want to test.
Thanks for reading! This should help you understand the concept of factory pattern. Stay tuned for more design patterns.
If you want to connect with me, you can find me on Twitter @abh1navv
Top comments (0)