Factory Method and Abstract Factory are two common ways to handle object creation. They sound similar, but their purpose and structure are a bit different.
- Factory Method Pattern
Idea: A single factory class decides which object to create, often based on input like a String or enum.
Pros:
Simple and centralized.
Good for small product sets.
Cons:
Adding new products requires modifying the factory (more if/else).
Coffee Shop Example:
CoffeeFactory has makeCoffee(String type).
You pass "latte" or "espresso", and it returns the right coffee object.
// Coffee interface
public interface Coffee {
void prepare();
}
// Concrete coffee types
public class Espresso implements Coffee {
@override
public void prepare() {
System.out.println("Grinding beans, brewing strong espresso...");
}
}
public class Latte implements Coffee {
@override
public void prepare() {
System.out.println("Brewing coffee, adding steamed milk...");
}
}
// Factory Method
public class CoffeeFactory {
public Coffee makeCoffee(String type) {
if (type.equalsIgnoreCase("espresso")) {
return new Espresso();
} else if (type.equalsIgnoreCase("latte")) {
return new Latte();
} else {
throw new IllegalArgumentException("Unknown coffee type: " + type);
}
}
}
// Client
public class Main {
public static void main(String[] args) {
CoffeeFactory factory = new CoffeeFactory();
Coffee coffee1 = factory.makeCoffee("espresso");
coffee1.prepare();
Coffee coffee2 = factory.makeCoffee("latte");
coffee2.prepare();
}
}
- Abstract Factory Pattern
Idea:
Instead of one factory with conditionals, you have an abstract factory interface with multiple concrete factories, each producing one specific type or a family of related products.
The client chooses which factory to use — no if/else needed inside the factory.
Pros:
No big conditional logic.
Easy to add new product types by creating a new factory.
Supports creating families of related products (e.g., coffee + tea sets).
Cons:
More classes to maintain.
May be overkill for small projects.
Coffee Shop Example:
EspressoFactory always makes Espresso.
LatteFactory always makes Latte.
// Coffee interface
public interface Coffee {
void prepare();
}
// Concrete coffee types
public class Espresso implements Coffee {
@override
public void prepare() {
System.out.println("Grinding beans, brewing strong espresso...");
}
}
public class Latte implements Coffee {
@override
public void prepare() {
System.out.println("Brewing coffee, adding steamed milk...");
}
}
// Abstract factory
public abstract class CoffeeFactory {
public abstract Coffee createCoffee();
}
// Concrete factories
public class EspressoFactory extends CoffeeFactory {
@override
public Coffee createCoffee() {
return new Espresso();
}
}
public class LatteFactory extends CoffeeFactory {
@override
public Coffee createCoffee() {
return new Latte();
}
}
// Client
public class Main {
public static void main(String[] args) {
CoffeeFactory espressoFactory = new EspressoFactory();
Coffee espresso = espressoFactory.createCoffee();
espresso.prepare();
CoffeeFactory latteFactory = new LatteFactory();
Coffee latte = latteFactory.createCoffee();
latte.prepare();
}
}
Top comments (0)