디자인 패턴 4강. 팩토리 패턴(Factory pattern)

기타/[고급객체지향 프로그래밍]

2019. 12. 2. 17:55

 

[기존 코드의 문제점]

: 다음과 같이 실행시의 주어진 조건에 따라 생성되는 구상 클래스 코드가 있을때.

Duck duck;
if (picnic) {
  duck = new MallardDuck();
} else if (hunting) {
  duck = new DecoyDuck();
} else if (inBathTub) {
  duck = new RubberDuck();
}

: 코드의 변경 및 확장할때 복잡해져 관리 및 갱신이 어려워진다.

 

# 무엇이 문제인가?

: 변화에 대해 닫혀 있는 코드의 모습

 

 

# 팩토리 패턴의 기본 구조

 

 

# 팩토리 패턴 예제 1 - 피자 가게

더보기

[1단계]

: SimplePizzaFactory로 피자 종류 선택하는 코드 분리만 해준 상태이다.

- PizzaStory 클래스 : factory에서 생성해줄 피자종류 받아와 공통 작업 수행(prepare, bake, cut, box)

public class PizzaStore {
    PizzaFactory pizzaFactory;

    public PizzaStore(PizzaFactory pizzaFactory){
        this.pizzaFactory = pizzaFactory;
    }

    Pizza orderPizza(String type) {  // type에 따라 만드는 피자 종류 달라진다

        // pizzafactory로 피자타입 선택하는 코드 분리해줘서 작성해야 하는 코드
        Pizza pizza;
        pizza = pizzaFactory.createPizza(type);

        // 공통된 부분(바뀌지 않는 부분)
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

- (Simple)PizzaFactory 클래스 : 주어진 type에 따라 생성할 피자 종류 선택 (아직 개선 필요한 형태)

public class PizzaFactory {
    public Pizza createPizza(String type){
        Pizza pizza = null;

        // 피자 추가 및 변경시 이 코드 일일히 수정해야한다.
        if (type.equals("cheese")){
            pizza = new CheesePizza();
        } else if (type.equals("greek")){
            pizza = new GreekPizza();
        } else if (type.equals("pepperoni")){
            pizza = new PepperoniPizza();
        }
        return pizza;
    }
}

- Pizza 클래스와 그 자식 클래스 : 생략. (prepare, bake, cut, box) 구현 필수

* 이상태만으론 패턴이라 할 수 없다(if문 만연..)

 

 

[2단계](파일로 존재)

: 아래 코드에서는 Pizza의 중간 코드 없이 바로 피자종류클래스가 상속받는 구조로 되어있으니 유의!

- PizzaStore 클래스 : Creator 클래스

public abstract class PizzaStore {
    void prepareToBoxing(Pizza pizza){ // 공통작업
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
    }
    Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);  //팩토리객체가 아닌 pizzastore에서 호출
        prepareToBoxing(pizza);
        return pizza;
    }
    abstract Pizza createPizza(String type);
    // 각 피자 가게지점에서 각 지점별 특색 피자들 만들기위해 추상화함.
}

 - NYPizzaStore 클래스 : ConcreteCreator 클래스

public class NYPizzaStore extends PizzaStore {
    Pizza createPizza(String type){
        Pizza pizza = null;
        if (type.equals("cheese")) { 
            pizza = new NYStyleCheesePizza();
        } else if (type.equals("pepperoni")) {
            pizza = new NYStylePepperoniPizza();
        } else if (type.equals("clam")) {
            //pizza = new NYStyleClamPizza();
        } else if (type.equals("veggie")) {
            //pizza = new NYStyleVeggiePizza();
        }
        return pizza;
    }
}

- Pizza 클래스 : Product 클래스

import java.util.ArrayList;

public abstract class Pizza {
    String name;
    String dough;
    String sauce;
    ArrayList toppings = new ArrayList();

    void prepare(){

        System.out.println( name+" 피자 준비중...");
        System.out.println("도우 전달중...");
        System.out.println("소스 추가중...");
        System.out.println("토핑 추가중 : ");
        for (int i = 0; i < toppings.size(); i++) {
            System.out.println(" " + toppings.get(i));
        }
    }
    void bake(){
        System.out.println("피자 굽는중...");
    }
    void cut(){
        System.out.println("피자 자르는중...");
    }
    void box(){
        System.out.println("피자 포장중...");
    }
    public String getName(){
        return name;
    }
}

- NYStylePepperoniPizza 클래스 : ConcreteProduct 클래스

public class NYStylePepperoniPizza extends Pizza{
    NYStylePepperoniPizza(){
        name = "뉴욕 스타일 소스와 페퍼로니 피자";
        dough = "얇고 크런치한 도우";
        sauce = "토마토 소스";
        toppings.add("토핑없음");
    }
}

 

 

[3단계](원재료 생산 공장) - 추상 팩토리 패턴

: 원재료를 생산하는 팩토리 생성 (코드 생략, 파일로 있음)

 

# 팩토리 패턴 예제 2 - IDcard와 소유자 생성 공장

더보기

 

: 예제에선 추상클래스인 product와 factory를 framework라는 패키지 안에 넣었고

: IDCard(ConcreteProduct)와 IDCardFactory(ConcreteFactory)는 idcard 패키지에 넣었다.

: 또한 concrete끼리 참조하지 않고, 위 추상클래스끼리 참조하는 방식으로 작성되었다.

 

# 코드 생략, 단, 파일엔 존재

 

 

# 팩토리패턴 예제 3 - Observer 패턴예제를 팩토리 패턴으로

더보기

: observer역할의 window들을 종류에 따라 메인 panel에 추가할때, factory이용해서 어떤종류의 observer를 추가할지 설정

기존 Observer 패턴 모양
factory 패턴 추가 모양

- OvserverWindowFactory(Creater 클래스)

- ConcreteObserverWindowFactory(ConcreteCreater 클래스)

  : 여기서 concreteCreater가 들어온 str값과 일치하는 product 선택해주는 코드 존재

- ObserverWindow(Product 클래스)

- LabelWindow, TextFieldWindow(Concrete 클래스)

 

: 코드 파일로 존재.