2023. 12. 30. 15:09ㆍServer/디자인패턴
Factory Method
팩토리 메서드 패턴이란 ?
객체를 생성할 때 필요한 인터페이스를 만들고, 어떤 클래스의 인스턴스를 만들지는 서브 클래스에서 결정하는 패턴
따라서 클래스 인스턴스를 만드는 일을 서브클래스에게 맡길 수 있다.
이전에 작성한 코드를 변경하며 살펴보겠습니다.
PizzaStore.java
public abstract class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type); //변경
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
protected abstract Pizza createPizza(String type); //추가
}
다음과 같이 추상 PizzaStore 클래스에 createPizza(type)을 통해 Pizza 인스턴스 객체를 생성하고, 객체를 생성하는 createPizza를 추상 메서드로 두었습니다.
이제 실제 제품을 구성하는 ‘추상’ Pizza 클래스를 보겠습니다.
public abstract class Pizza {
String name;
String dough;
String sauce;
List<String> toppings = new ArrayList<>();
void prepare(){
System.out.println("준비 중: "+ name);
System.out.println("도우를 돌리는 중...");
System.out.println("소스를 뿌리는 중...");
System.out.println("토핑을 올리는 중...");
for (String topping : toppings){
System.out.println(" "+ topping);
}
}
void bake(){
System.out.println("175도에서 25분 간 굽기");
}
void cut(){
System.out.println("피자를 사선으로 자르기");
}
void box(){
System.out.println("상자에 피자 담기");
}
public String getName(){
return name;
}
추상 클래스를 만들었으니, 실제 구상 클래스가 필요할 것입니다. 각 도시별 치즈 피자만 만들어 보겠습니다.
public class NYStyleCheesePizza extends Pizza{
public NYStyleCheesePizza(){
name = "뉴욕 스타일 소스와 치즈 피자";
dough = "씬 크러스트 도우";
sauce = "마라나라 소스";
toppings.add("잘게 썬 레지아노 치즈");
}
}
public class ChicagoStyleCheesePizza extends Pizza{
public ChicagoStyleCheesePizza(){
name = "시카고 스타일 딥 디쉬 치즈 피자";
dough = "아주 두꺼운 크러스트 도우";
sauce = "플럼 토마토 소스";
toppings.add("잘게 조각낸 모짜렐라 치즈");
}
void cut(){
System.out.println("네모난 모양으로 피자 자르기");
}
}
이 후 각 요구사항 별로 다른 도시에서 주문한 피자를 조회하는 실행 코드를 작성해보겠습니다.
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("에단이 주문한 "+ pizza.getName());
pizza = chicagoStore.orderPizza("cheese");
System.out.println("조엘이 주문한 "+ pizza.getName());
}
}
각자 다른 도시의 Store를 생성하고, 해당 가게에서 orderPizza를 호출하여 각기 다른 스타일의 피자를 반환받을 수 있습니다.
output:
준비 중: 뉴욕 스타일 소스와 치즈 피자
도우를 돌리는 중...
소스를 뿌리는 중...
토핑을 올리는 중...
잘게 썬 레지아노 치즈
175도에서 25분 간 굽기
피자를 사선으로 자르기
상자에 피자 담기
에단이 주문한 뉴욕 스타일 소스와 치즈 피자
준비 중: 시카고 스타일 딥 디쉬 치즈 피자
도우를 돌리는 중...
소스를 뿌리는 중...
토핑을 올리는 중...
잘게 조각낸 모짜렐라 치즈
175도에서 25분 간 굽기
네모난 모양으로 피자 자르기
상자에 피자 담기
조엘이 주문한 시카고 스타일 딥 디쉬 치즈 피자
다이어그램
코드 만으로는 이해가 쉽지 않을 것 같아 저만의 다이어그램을 그려보았습니다.
추상 클래스인 PizzaStore에는 orderPizza 가 구현되어 있습니다.
하지만 createPizza는 추상 메소드로 존재합니다.
각 도시별 가게인 NYPizzaStore, ChicagoPizzaStore 에는 각 도시별 스타일의 Pizza를 구현합니다.
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else {
return null;
}
위 예시처럼, 종류별로 해당 도시 스타일의 피자를 생성합니다.
그럼 이제 제품을 담당하는 추상 클래스인 Pizza를 보겠습니다.
Pizza 추상 클래스의 멤버는 이렇게 존재합니다.
String name;
String dough;
String sauce;
List<String> toppings = new ArrayList<>();
void prepare(){
System.out.println("준비 중: "+ name);
System.out.println("도우를 돌리는 중...");
System.out.println("소스를 뿌리는 중...");
System.out.println("토핑을 올리는 중...");
for (String topping : toppings){
System.out.println(" "+ topping);
}
}
void bake(){
System.out.println("175도에서 25분 간 굽기");
}
void cut(){
System.out.println("피자를 사선으로 자르기");
}
void box(){
System.out.println("상자에 피자 담기");
}
public String getName(){
return name;
}
또한, 해당 추상 클래스를 상속받는 NYCheesePizza, ChicagoCheesePizza 가 존재하며, 이들은 각 특성에 따라
name, dough, sauce, toppings를 재정의합니다.
각 도시별 Store는 재정의 된 도시별 피자를 Pizza 종류 (String type
) 에 따라 동적으로 생성합니다.
정리하자면, NYPizzaStore, ChicagoPizzaStore 등 PizzaStore의 서브클래스의 종류에 따라NYCheesePizza, (or NY어쩌구Pizza) 혹은 ChicagoCheesePizza, (or Chicago어쩌구Pizza) 와 같이 생산되는 객체 인스턴스가 결정되게 됩니다.
이러한 구조를 갖는 디자인 패턴을 팩토리 메서드 패턴 이라고 합니다.
보시다시피 팩토리 메서드 패턴은 추상클래스를 이용하여 구현합니다. 따라서 서브클래스의 공통된 부분은 구현하지 않고 그대로 사용하고, 변경이 필요한 부분( 위 예시에서는 피자를 생성하는 createPizza() )을 재정의 하는 방식으로 구현하게 됩니다.
다음 포스팅에서는 Abstract Factory Method 패턴을 알아보겠습니다.
'Server > 디자인패턴' 카테고리의 다른 글
Simple Factory (1) | 2023.12.30 |
---|