디자인 패턴 - 추상 팩토리 패턴

안성은·2022년 4월 10일
0

Disign Pattern

목록 보기
3/9
post-thumbnail

추상 팩토리 패턴

  • 정의
    • 추상 팩토리 패턴에서는 인터페이스를 이용해서 서로 연관된 혹은 의존하는 객체를 구현 클래스를 지정하지 않고 생성하는 패턴
  • 사용하는 이유
    • 추상 팩토리를 통해서 객체를 생성하기 위한 인터페이스 제공 가능하다. 이를 통해 실제 객체를 생성하는 팩토리와 분리시켜 각 요구조건에 상응하는 객체를 제공하는 다양한 팩토리를 구현 가능하다.
    • 서로 연관된 일련의 객체를 만들어야 할 때 사용하면 좋지만 새로운 객체를 추가하거나 확장할 때 인터페이스를 수정해야하고 관련된 서브 클래스의 인터페이스를 전부 수정해야한다는 단점이 존재한다.
  • 방법

  • 실제 적용 UML

  • 레거시 코드
public class LegacyPizza {
    String name;
    Dough dough;
    Sauce sauce;
    Cheese cheese;

    public void prepare(String pizzaStoreName) {

        DoughFactory doughFactory   = new DoughFactory();
        SauceFactory sauceFactory   = new SauceFactory();
        CheeseFactory cheeseFactory = new CheeseFactory();

        dough  = doughFactory.selectDough(pizzaStoreName);
        sauce  = sauceFactory.selectSauce(pizzaStoreName);
        cheese = cheeseFactory.selectCheese(pizzaStoreName);
    }
    
}

//store가 많이 질수록 팩토리 객체를 생성하는 부분이 더욱 길어지는 문제 발생.

public class DoughFactory {

    public DoughFactory() {}

    public Dough selectDough(String pizzaStoreName) {
        if (pizzaStoreName.equals("store1")) {
            return new ThinCrustDough();
        } else if (pizzaStoreName.equals("store2")) {
            return new ThickCrustDough();
        } else {
            System.out.println("error:  Invalid Store");
        }
        return null;
    }
}

public class SauceFactory{

    public SauceFactory() {}

    public Sauce selectSauce(String pizzaStoreName) {
        if (pizzaStoreName.equals("store1")) {
            return new MarinaraSauce();
        } else if (pizzaStoreName.equals("store2")) {
            return new TomatoSauce();
        } else {
            System.out.println("error:  Invalid Store");
        }
        return null;
    }
}

public class CheeseFactory{

    public CheeseFactory() {}

    public Cheese selectCheese(String pizzaStoreName) {
        if (pizzaStoreName.equals("store1")) {
            return new RegianoCheese();
        } else if (pizzaStoreName.equals("store2")) {
            return new ChedaCheese();
        } else {
            System.out.println("error:  Invalid Store");
        }
        return null;
    }
}


  • 개선 과정 및 코드
    • 디렉토리 구조
  • 개선 코드
    • PizzaIngredientFactory 추상화
public interface PizzaIngredientFactory {
    Dough createDough();
    Sauce createSauce();
    Cheese createCheese();
}
  • PizzaIngredientFactory 구현체
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{

    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }

    @Override
    public Sauce createSauce() {
        return new MarinaraSauce();
    }

    @Override
    public Cheese createCheese() {
        return new RegianoCheese();
    }
    
}
  • PizzaIngredient 추상화
public abstract class Dough {
    String name;
    String type;

    @Override
    public String toString() {
        return "Cheese{" +
                "name='" + name + '\'' +
                ", type='" + type + '\'' +
                '}';
    }
}
  • PizzaIngredient 구현체
public class ThinCrustDough extends Dough{

    public ThinCrustDough() {
        name = "ThinCrustDough";
        type = "ThinCrust";
    }
}
  • Pizza 추상화
public abstract class Pizza {
    String name;
    Dough dough;
    Sauce sauce;
    Cheese cheese;

    public abstract void prepare();

    public void bake() {
        System.out.println("Bake for 25 minutes at 350");
    }

    public void cut() {
        System.out.println("Cutting the pizza into 8 slices");
    }

    public void box() {
        System.out.println("Place pizza in official PizzaStore box");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Pizza{" +
                "name='" + name + '\'' +
                ", dough=" + dough +
                ", sauce=" + sauce +
                ", cheese=" + cheese +
                '}';
    }
}
  • Pizza 구현체
public class CheesePizza extends Pizza{

    PizzaIngredientFactory pizzaIngredientFactory;

    public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory) {
        this.pizzaIngredientFactory = pizzaIngredientFactory;
    }

    @Override
    public void prepare() {
        System.out.println("Preparing " + name);
        super.dough = pizzaIngredientFactory.createDough();
        super.sauce = pizzaIngredientFactory.createSauce();
        super.cheese = pizzaIngredientFactory.createCheese();
    }
}
  • PizzaStore 추상화
public abstract class PizzaStore {

    protected abstract Pizza createPizza(String type);

    public Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}
  • PizzaStore 구현체
public class NYPizzaStore extends PizzaStore {

    @Override
    protected Pizza createPizza(String type) {

        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();


        if (type.equals("cheese")) {
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("New York Style Cheese Pizza");
        } else if (type.equals("peppernoni")) {
            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("New York Style Pepperoni Pizza");
        } else {
            return null;
        }

        return pizza;
    }
}
  • TEST CODE

    public class PizzaCreateTest {
       public static void main(String[] args) {
           PizzaIngredientFactory pizzaIngredientFactory = new NYPizzaIngredientFactory();
           pizzaIngredientFactory.createDough();
           pizzaIngredientFactory.createCheese();
           pizzaIngredientFactory.createSauce();
    
           PizzaStore NYPizzaStore = new NYPizzaStore();
    
           Pizza pizza = NYPizzaStore.orderPizza("cheese");
           System.out.println("order success: " + pizza1.toString() + "\n");
       }
    }

0개의 댓글