[디자인 패턴] 팩토리 메소드(Factory Method) 패턴
0. 이 글을 쓰게된 이유
토비의 스프링을 공부하던 중 팩토리 메소드 패턴에 대한 이야기가 나왔다. 경험해본 패턴이라 알고는 있었지만 정리가 되지 않은거 같아 이 글을 쓰게 되었다.
1. 팩토리 메소드 패턴이란?
팩토리 메소드 패턴은 생성 패턴 중 하나로, 객체를 생성할 때 어떤 클래스의 인스턴스를 만들지 서브 클래스에서 결정하게 되는 패턴이다.
추상 클래스인 Creator는 factoryMethod를 통해 Product 인터페이스 타입의 인스턴스를 생성하도록 설계되어있다고 하자.
추상 클래스인 Creator를 상속 받은 서브 클래스 Creator1이 factoryMethod를 오버라이딩해서 Product 인터페이스 타입의 클래스 중 어떤 구체 클래스를 사용하여 인스턴스를 만들지 결정하는 구조이다.
2. Example
2.1 Product(Food)
public interface Food {
void recipe();
}
public class Pizza implements Food {
@Override
public void recipe() {
System.out.println("반죽하고 토핑 넣고 오븐에 넣기");
}
}
Food라는 인터페이스가 있고 Pizza는 그것을 상속받는 구체 클래스
2.2 Creator(FoodFactory)
public abstract class FoodFactory {
public Food newInstance() {
Food food = createFood();
food.recipe();
return food;
}
protected abstract Food createFood();
}
public class PizzaFoodFactory extends FoodFactory {
@Override
protected Food createFood() {
return new Pizza();
}
}
FoodFactory는 추상 클래스이고 newInstance()에서 같은 클래스 내에 있는 createFood를 호출하고있음.
여기서 createFood를 factory method라고 함.
PizzaFoodFactory는 FoodFactory를 상속 받고 factory method인 createFood를 오버라이딩하여 구체 클래스인 Pizza를 생성.
2.3 Client Code
FoodFactory foodFactory = new PizzaFoodFactory();
Food food = foodFactory.newInstance();
// 출력 : 반죽하고 토핑 넣고 오븐에 넣기
정리
위 코드가 전형적인 팩토리 메소드 패턴 중 하나라고 볼 수 있다.
Food라는 Product가 있고 그를 구현하는 Pizza라는 구체적인 클래스가 있다.
Creator인 FoodFactory는 추상 클래스이며 createFood()라는 factory method를 통해 Food 타입의 인스턴스를 생성해야한다고 강제하고 있다.
하지만 이 FoodFactory라는 추상 클래스에서 직접 객체를 생성할 수 없고 이를 상속 받는 서브 클래스에서 어떤 객체를 생성할지 결정한다.
FoodFactory를 상속 받은 PizzaFactory에서 createFood()라는 factory method를 오버라이딩해서 Food 인스턴스 타입인 Pizza 인스턴스를 생성한다.
3. 팩토리 메소드의 장점
만약 위 예시를 확장한다고 해보자. 새로운 음식인 Chicken이 생겼다.
public class Chicken implements Food {
@Override
public void recipe() {
System.out.println("닭을 분리하고 튀김가루 묻혀서 튀김.");
}
}
이 치킨을 제공하는 Creator코드인 ChickenFactory를 만든다.
public class ChickenFactory extends FoodFactory {
@Override
protected Food createFood() {
return new Chicken();
}
}
다음과 같이 활용만 하면 됨.
FoodFactory chickenFactory = new ChickenFactory();
Food chicken = chickenFactory.newInstance();
3.1 장점 정리
위 코드를 봤을 때 기존 코드에 수정이 일어나지 않는다. 그 대신 확장되는 기능에 대해 추가만 해주면 된다.
이는 Solid원칙 중 하나인 OCP(개방폐쇄 원칙)를 지킨다. 즉, 이 패턴은 변경에는 닫혀있고 확장에는 열려있는 코드인 것이다.
4. 팩토리 메소드의 단점
간단한 기능을 추가해도 많은 클래스를 정의해야 한다.
예제 코드는 오버라이딩 하는 메소드가 하나였지만 많아졌을 때 상당히 불편하다.
5. 팩토리 메소드의 활용성
- 어떤 클래스가 자신이 생성해야 하는 객체의 클래스를 예측할 수 없을 때
이 때에는 클래스를 추상 클래스로 만들고 팩토리 메소드를 활용할 수 있다. - 생성할 객체를 기술하는 책임을 자신의 서브클래스가 지정했으면 할 때
- 객체 생성의 책임을 몇 개의 보조 서브클래스 가운데 하나에게 위임하고, 어떤 서브클래스가 위임자인지에 대한 정보를 국소화시키고 싶을 때