simple factory and factory method pattern - java -explained
Intent
Simple Factory
This is actually not a design pattern but a programming idiom.
Use Simple Factory when you want to abstract the object creation only but when the intention is to create a framework which is responsible from the creation of an object to the management of the object then think about using Factory Method pattern.
The factory method internally uses a Simple Factory pattern.
Factory Method
Define an interface for creating an object, but let the subclass decide which class to instantiate. The factory method lets a class defer instantiation to subclasses. It's a creational pattern.
Understanding Simple Factory pattern
A simple factory is about to provide an abstraction to the object creation.
Example ( famous pizza shop example from head first design pattern book )
public interface Pizza {
void prepare();
void bake();
void cut();
void box();
}
***********
public class PizzaStore {
private static SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();
public static void main(String[] args) {
System.out.println("Order cheese pizza");
orderPizza("cheese");
System.out.println("Order cheese pizza");
orderPizza("veggie");
}
public static Pizza orderPizza(String type) {
Pizza pizza = simplePizzaFactory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
***********
public class SimplePizzaFactory {
public Pizza createPizza(String type) {
Pizza pizza = null;
if (type.equals("cheese")) {
pizza = new CheesePizza();
}
if (type.equals("veggie")) {
pizza = new VeggiePizza();
}
return pizza;
}
}
***********
public class VeggiePizza implements Pizza {
@Override
public void prepare() {
System.out.println("preparing veggie pizza");
}
@Override
public void bake() {
System.out.println("preparing veggie pizza");
}
@Override
public void cut() {
System.out.println("preparing veggie pizza");
}
@Override
public void box() {
System.out.println("preparing veggie pizza");
}
}
public class CheesePizza implements Pizza {
@Override
public void prepare() {
System.out.println("preparing cheese pizza");
}
@Override
public void bake() {
System.out.println("baking cheese pizza");
}
@Override
public void cut() {
System.out.println("currint cheese pizza");
}
@Override
public void box() {
System.out.println("boxing cheese pizza");
}
}
In the example above we have delegated object creation responsibility to the strategy class.
understanding the factory method pattern.
(explaining example from head first design pattern book) Suppose a Business comes up with an idea to create a franchise for our store, like NyStylePizzaStore and ChicagoStylePizzaStore . Here business wants to localize pizza making activities to the PizzaStore class but also want to give flexibility to the franchise classes to alter some activities as per their choices and demand from their respective region.
code example
****** Main client class
public class PizzaTestDrive {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
pizza = nyStore.orderPizza("clam");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("clam");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
pizza = nyStore.orderPizza("pepperoni");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("pepperoni");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
pizza = nyStore.orderPizza("veggie");
System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("veggie");
System.out.println("Joel ordered a " + pizza.getName() + "\n");
}
}
****** creator which has an abstract method.
public abstract class PizzaStore {
String name;
abstract Pizza createPizza(String item);
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
pizza.bake();
pizza.cut();
pizza.prepare();
pizza.box();
return pizza;
}
}
****** concrete implementation of store with implementation for createPizza
public class ChicagoPizzaStore extends PizzaStore {
public ChicagoPizzaStore() {
this.name = "chicago style pizza";
}
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new ChicagoStyleCheesePizza();
} else if (item.equals("veggie")) {
return new ChicagoStyleVeggiePizza();
} else if (item.equals("clam")) {
return new ChicagoStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new ChicagoStylePepperoniPizza();
} else
return null;
}
public String getName() {
return this.name;
}
}
public class NYPizzaStore extends PizzaStore {
public NYPizzaStore() {
super.name = "Ny style pizza";
}
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if (item.equals("clam")) {
return new NYStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else
return null;
}
public String getName() {
return this.name;
}
}
An important point to note here is the abstract PizzaStore class and how in factory method pattern subclass defines which object to instantiate.
In the above code , PizzaStore is our interface for creating an object but actual object creation is done by the respective concrete stores.
*******************OUTPUT******************************
--- Making a NYStyleCheesePizza ---
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
prepare ny style cheese pizza
Place pizza in official PizzaStore box
Ethan ordered a NYStyleCheesePizza
--- Making a ChicagoStyleCheesePizza ---
Bake for 25 minutes at 350
Cutting the pizza into square slices
preparing chicago style cheese pizza
Place pizza in official PizzaStore box
Joel ordered a ChicagoStyleCheesePizza
--- Making a NYStyleClamPizza ---
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
preparing nystyle calm pizza
Place pizza in official PizzaStore box
Ethan ordered a NYStyleClamPizza
--- Making a ChicagoStyleClamPizza ---
Bake for 25 minutes at 350
Cutting the pizza into square slices
prepare chicago style calm pizza
Place pizza in official PizzaStore box
Joel ordered a ChicagoStyleClamPizza
--- Making a NYStylePepperoniPizza ---
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
preparing NYStyle pepperoni pizza
Place pizza in official PizzaStore box
Ethan ordered a NYStylePepperoniPizza
--- Making a ChicagoStylePepperoniPizza ---
Bake for 25 minutes at 350
Cutting the pizza into square slices
prepare chicago style pepperoni pizza
Place pizza in official PizzaStore box
Joel ordered a ChicagoStylePepperoniPizza
--- Making a NYStyleVeggiePizza ---
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Preparing NyStyle veggie pizza
Place pizza in official PizzaStore box
Ethan ordered a NYStyleVeggiePizza
--- Making a ChicagoStyleVeggiePizza ---
Bake for 25 minutes at 350
Cutting the pizza into square slices
prepare chicago style veggie pizza
Place pizza in official PizzaStore box
Joel ordered a ChicagoStyleVeggiePizza
********************************************************
Structure : Factory Method Pattern
product , concreteproduct , creator and concrete creator are main components in the structure.
click here to open image in new tab
1) Product : defines the interface for multiple concrete products to create by the concrete creator .
2) Concrete Products: this implements the Product.
This is actually created by the concrete creator with return type as Product but internally contains ConcreteProduct.
3) Creator : This contains the factory method which must be implemented by concrete creator . Apart from the factory method(abstract), creator also has many business-specific methods few of them might be using Product that we'll be creating using the abstract method implemented in concrete creator.
4) ConcreteCreator : This overrides the factory method and returns the instance of ConcreteProduct.
Applicability
Use factory method when you want to decouple product construction(object creation) code from the main logic. Only product construction code is decoupled but rest of the business logic related to the product can be write using product interface.
When a class wants its sub-classes to specify the objects it creates then use factory method.
Pros
Pros
- we avoid tight coupling between he creator and concrete products.
- open/close principle : adding new product types is easy and open without changing existing business logic code.
- single responsibility principle : by delegating object creation to factory method we achieve single responsibility principle , internally factory method takes care which product to create.
- client might have to subclass of the Creator class just to create a particular ConcreteProduct object.
Relations with other patterns
- Abstract factory pattern mostly implemented with factory pattern as the base.
- Factory method patterns are usually called in the template method.
- For the object creation and management many designs starts with factory method and then evolve towards AbstractFactory, Prototype or builder pattern which are more complicated to build.
- As a factory pattern based on Inheritance, a prototype pattern is not based on Inheritance, the prototype requires a complicated initialization of the cloned object.
- Factory method is specialization of the Template Method pattern.
Subscribe to my newsletter
Read articles from Aditya Chaudhari directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Aditya Chaudhari
Aditya Chaudhari
building efficient, scalable and maintainable enterprise e-commerce applications | Technical Architect | SAP Commerce Cloud (hybris) | Java | Spring | Mirakl