[자바 디자인패턴(Java Design Pattern) #5] 추상 팩토리 패턴(Abstract Factory Pattern) - 제품군을 형성해 보자. Java

앞선 포스팅 에서는, 팩토리 메소드 패턴을 주제로 이야기 해 보았다.
지금부터 할 이야기는 이 후속 편이될 추상 팩토리 패턴인데, 팩토리 메소드 패턴을 아직 잘 모르는 분들은 
이해를 돕기 위하여 전 포스팅을 꼭 한번 읽어보고 오시면 좋을듯하다.

<팩토리 메소드 패턴 포스팅 보러가기>
======================================================================================

자! 그럼 이제부터 추상 팩토리 패턴을 알아보자.

이것은 팩토리 메소드 패턴과 비슷하면서도 확실히 다르다.
두가지를 비교해 보기 위하여 각각의 정의를 적어 보겠다.

팩토리 메소드 패턴 : 객체를 생성하기 위한 인터페이스를 만듭니다. 어떤 클래스의 인스턴스를 만들지는 서브클래스에서 결정하도록 합니다. 팩토리 메소드를 이용하면 인스턴스를 만드는 일을 서브클래스로 미룰 수 있습니다.

추상 팩토리 패턴 : 서로 연관된, 또는 의존적인 객체들로 이루어진 제품군을 생성하기 위한 인터페이스를 제공합니다. 구상 클래스는 서브클래스에 의해 만들어 집니다.

자, 역시나! 정의만 봐서는 이해가 잘 안가실 수 있습니다.
그래서 오늘도, 팩토리 메소드 패턴이 아닌 추상 팩토리 패턴을 사용한 피자가게 예제를 들어보도록 하겠습니다.
함께 보시죠.

======================================================================================

자, 일단 이 패턴의 전체 그림을 놓고 본다면 크게 3가지 분류가 있습니다.

1. 생산자(Creator) : 실제로 완성된 제품을 내놓는 객체 입니다. 여기서는 피자가게(PizzaStore)가 되겠네요

2. 제품(Product) : 말그대로 제품입니다. 제품을 만들기 위해서는 내부 재료나 처리 방식등을 정해야 하죠. 이번 예제에서는 피자(Pizza)에 해당합니다.

3. 재료들(Ingredients) : 제품에 들어가는 모든 재료들을 이야기 합니다. 재료는 다양하게 존재할 수 있고 그중에는 비슷한 속성을 지닌 재료들도 있을 것입니다. 이번 예제에서는 도우(Dough-피자에 베이스 반죽), 치즈(Cheese), 소스(Sauce), 채소들(Veggie[]) 등이 있겠네요.

그럼 이제부터 하나씩 차근차근 살펴보도록 하겠습니다. (이전 포스팅과 객체명을 달리하기위해 '2'를 붙였습니다.)

======================================================================================

1. 피자 재료 공장 인터페이스 (PizzaIngredientFactory)

  - 모든 재료공장의 Base 형태가 되어줄 인터페이스
  - 각 세부 재료 항목에 대한 팩토리 메소드를 지니고 있다.
  - 세부 재료(Dough,Cheese,Sauce,Veggies) 에 대한 인터페이스는 이미 구현되어있다고 가정한다. 

public interface PizzaIngredientFactory {
public Dough createDough();
public Cheese createCheese();
public Sauce createSauce();
public Veggies[] createVeggies();
}

2. 피자 추상클래스 (Pizza2)

  - 모든 피자 객체의 Base가 될 추상클래스
  - 앞서 적었던 포스팅#4의 Pizza와는 달리 준비 재료를 각자 다르게 지정하기 위하여 prepare()를 abstract화 시켰다.
  - 필드변수를 보면 특정 피자의 재료가 될 수 있는 재료군을 볼 수 있다. (여기에 직접 재료를 할당하는 작업을 서브클래스에서 구현할 것이다.)

public abstract class Pizza2 {
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
abstract void prepare();
public void bake(){
System.out.println("Bake for 25 min at 350");
}
public void cut(){
System.out.println("Cutting the pizza into diagonal slices");
}
public void box(){
System.out.println("Place the pizza in the box");
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
}


3. 피자 가게 (PizzaStore2) 추상클래스

  - 피자가 판매될 판매점의 Base가 될 함수 입니다.
  - 실제 클라이언트에서 사용하게 될 orderPizza()가 있고, 각 분점에서 구현해주어야 하는 팩토리 메소드 createPizza()가 있습니다.


public abstract class PizzaStore2 {
// 실제 외부에서 피자 주문 시 사용하게 될 Method
public Pizza2 orderPizza(String type){
Pizza2 pizza = createPizza(type);
// 피자 주문시 행하는 일련의 작업진행
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
// Factory Method (서브클래스에서 구현)
protected abstract Pizza2 createPizza(String type); 

}

여기까지가 Base역할을 하게될 추상클래스와, 인터페이스 코드였습니다.
그럼 이제 이 각각에 대해 세부 구현이 포함된 구상클래스와 그 용법을 보도록 하죠.

======================================================================================

4. 뉴욕 재료 공장 클래스 : 뉴욕 지점에서 만드는 모든피자의 재료를 제공할 구상 클래스

  - 피자의 각 재료군에 대한 팩토리 메소드를 가지고 있다.
  - 추상팩토리 패턴의 핵심이라고 할수 있다.
  - 파란색 부분이 각 재료군의 기본 틀이 된다고 볼 수 있는 인터페이스 이고, 빨간 객체들이 각 재료군을 구현(implement)한 구상 클래스가 되겠다.

public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
// 각 재료군에 대한 팩토리 메소드
// 현재는 전부다 단일 객체로 리턴이 되어있지만 실제로 인자값을 받아 여러 형태의 재료를 제공할 수 있다.
@Override
public Dough createDough() {
return new ThinCrustDough();
}
@Override
public Cheese createCheese() {
return new ReggianoCheese();
}
@Override
public Sauce createSauce() {
return new MarinaraSauce();
}
@Override
public Veggies[] createVeggies() {
Veggies[] veggies = {new Garlic(), new Onion()};
return veggies;
}
}

5. 뉴욕 치즈피자 클래스 : 뉴욕 지점에서만 제공하는 피자

- 뉴욕 재료 공장을 인자값으로 전달받아 객체를 초기화 한다.
- 해당 피자를 생산하기 위해 필요한 재료만을 재료공장에서 선별적으로 얻을 수 있다.

public class NYCheesePizza extends Pizza2{
PizzaIngredientFactory ingredientFactory;

public NYCheesePizza(PizzaIngredientFactory ingredientFactory) {
// 생성자에서 재료공장을 넘겨받아 필드변수로 저장한다
this.ingredientFactory = ingredientFactory;
}

@Override
void prepare() {
System.out.println("Preparing "+name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}

6. 뉴욕 피자 판매점  클래스 : 뉴욕지점에서 제공하는 모든 피자를 직접 주문할 수 있는 클래스

- 피자 객체를 생성하는 팩토리 메소드를 가진다.
- 피자 객체 생성을 위해 해당 지점에서만 제공되는 자체 재료공장 객체(IngredientFactory)를 가진다.
- 자체 재료공장클래스는 지점에서 생산 가능한 모든 피자객체의 생성자에 전달되어 재료를 종류별로(Dough, Cheese, Sauce 등) 조달한다.

public class NYPizzaStore2 extends PizzaStore2{

@Override
protected Pizza2 createPizza(String type) {
Pizza2 pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if(type.equals("cheese")){
pizza = new NYCheesePizza(ingredientFactory);
pizza.setName("New York style Cheese Pizza");
}else if (type.equals("veggie")){
pizza = new NYCheesePizza(ingredientFactory);
pizza.setName("New York style Veggie Pizza");
}
return null;
}

}

======================================================================================

그럼 이것으로 추상팩토리 패턴에 대한 포스팅을 마친다. ㅎㅎ
실제로는 각 재료군에 대한 인터페이스와 구상클래스 구현, 그리고 Driver클래스 와 Main 함수 구현이 있어야 하지만 이것은 너무 글이 길어지고, 또 구현하기 나름이기에 독자들의 상상력? 혹은 창의력에 맡긴다.
(나머지 코드를 완성하여 동작해보는 것도 연습이 되지 않을까요? ㅎㅎㅎㅎ)
.
.
.
추상팩토리는 하나의 기본 형태에 대해 굉장히 다양한 서브클래스를 제공해야 할때, 매우 유용한 패턴이라고 생각한다.

단순히 한가지 제품에 대한 다양한 제공 보다도 그 제품의 동작과 내부필드 객체마저 추상화된 객체들로 구성하여 코드의 유연함을 극대화 시킨 형태라고 볼 수 있다.

그럼 오늘은 이것으로 끝 !!!

핑백



통계 위젯 (블랙)

5745
703
304555

GoogleAdsenseResponsive

Cluster map