[๋””์ž์ธํŒจํ„ด] ํŒฉํ† ๋ฆฌ ํŒจํ„ด (Factory Pattern)

๋ฐ˜์‘ํ˜•
๐Ÿ’ก ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ ํŒจํ„ด (Factory Method Pattern)
๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•˜๋Š”๋ฐ, ์–ด๋–ค ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์ง€๋Š” ์„œ๋ธŒํด๋ž˜์Šค์—์„œ ์ •ํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. ์ฆ‰, ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ ํŒจํ„ด์„ ์ด์šฉํ•˜๋ฉด ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ์ผ์„ ์„œ๋ธŒํด๋ž˜์Šค์—๊ฒŒ ๋งก๊ธฐ๋Š” ๊ฒƒ
๐Ÿ’ก ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด (Abstract Factory Pattern)
์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด์šฉํ•˜์—ฌ ์„œ๋กœ ์—ฐ๊ด€๋œ, ๋˜๋Š” ์˜์กดํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๊ตฌ์ƒ ํด๋ž˜์Šค๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ์ƒ์„ฑ

1.  ๊ฐ„๋‹จํ•œ ํŒฉํ† ๋ฆฌ (Simple Factory)

1) ๋ฌธ์ œ์ธ์‹

๋‹ค์Œ๊ณผ ๊ฐ™์ด new ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•˜๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์•„๋‹Œ ํŠน์ • ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

Pizza pizza = new CheesePizza();
// Pizza pizza : ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์จ์„œ ์œ ์—ฐํ•˜๊ฒŒ ๋งŒ๋“œ๋ ค๊ณ  ํ•œ๋‹ค.
// new CheesePizza(); : ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๊ตฌ์ƒํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.

์—ฌ๋Ÿฌ๊ฐœ์˜ ๋‹ค์–‘ํ•œ ๊ตฌ์ƒ ํด๋ž˜์Šค๊ฐ€ ์กด์žฌํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์ƒ๊ธด๋‹ค.

public Pizza orderPizza (String type) {  // ์–ด๋–ค ํ”ผ์ž๋ฅผ ์กฐ๋ฆฌํ• ์ง€ type ์„ ์ด์šฉํ•˜์—ฌ
    Pizza pizza;
    if(type.equals("cheese")) {    // ๊ฐ ํ”ผ์ž์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ์ฒด ์ƒ์„ฑ
        pizza = new CheesePizza();
    } else if (type.equals("hawaiian")) {
        pizza = new HwaiianPizza();
    } else if (type.equals("pepperoni")) {
        pizza = new PepperoniPizza();
    }
    // ํ”ผ์ž ์กฐ๋ฆฌ ๋ฉ”์†Œ๋“œ๋“ค.. ์ƒ๋žต
    return pizza;
}

์ด ๊ฒฝ์šฐ ๋ณ€๊ฒฝ ๋˜๋Š” ํ™•์žฅ์„ ํ•  ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์ปค์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค. ์ฝ”๋“œ ์ˆ˜์ •์ด ํ•„์—ฐ์ฝ” ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ฆ‰, "๋ณ€ํ™”" ๋˜๋Š” ๊ฒƒ ๋•Œ๋ฌธ์— new ์˜ ์‚ฌ์šฉ์„ ์ฃผ์˜ํ•ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

์ด ๋•Œ๋ฌธ์— ์ธํ„ฐํŽ˜์ด์Šค์— ๋งž์ถฐ์„œ ์ฝ”๋”ฉํ•˜๋ผ๋Š” ๋ง์„ ํ•˜๊ณ ๋Š” ํ•œ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๋งŒ๋“ค๋ฉด, ๋‹คํ˜•์„ฑ ๋•Œ๋ฌธ์— ์–ด๋–ค ํด๋ž˜์Šค๋“  ํŠน์ • ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ๊ตฌํ˜„ํ•˜๋ฉด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฐ˜๋Œ€๋กœ, ๊ตฌ์ƒ ํด๋ž˜์Šค๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋ฉด ์ƒˆ๋กœ์šด ๊ตฌ์ƒ ํด๋ž˜์Šค๊ฐ€ ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค ์ฝ”๋“œ๋ฅผ ๊ณ ์ณ์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ณผ์ •์—์„œ ๋งŽ์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์‹œ๋งํ•˜๋ฉด ์ธํ„ฐํŽ˜์ด์Šค์— ๋งž์ถฐ ์ฝ”๋”ฉํ•˜๋ฉด ๋ณ€ํ™”์— ๋Œ€ํ•ด ๋‹ซํ˜€ ์žˆ๋Š” ์ฝ”๋“œ๊ฐ€ ๋œ๋‹ค. OCP ์›์น™์„ ์ค€์ˆ˜ํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

๐Ÿ“Œ ๋””์ž์ธ ์›์น™
      OCP (Open - Closed Principle) ์›์น™ , ๊ฐœ๋ฐฉ ํ์‡„ ์›์น™
      ํ™•์žฅ์— ๋Œ€ํ•ด ์—ด๋ ค ์žˆ์–ด์•ผ ํ•˜๊ณ , ์ˆ˜์ •์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ซํ˜€ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ์›์น™
      ํ™•์žฅ์— ๋Œ€ํ•ด์„œ๋Š” Open , ๋ณ€๊ฒฝ์— ๋Œ€ํ•ด์„œ๋Š” Closed ํ•˜๋ผ๋Š” ์›์น™

์œ„์˜ pizza ํด๋ž˜์Šค ์ƒ์„ฑ๊ณผ์ •์„ ํ†ตํ•ด ๊ตฌ์ƒ ํด๋ž˜์Šค๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ฝ”๋”ฉ์„ ํ•˜๋ฉด ๋‚˜์ค‘์— ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•ด์•ผํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง€๊ณ , ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ํ”ผํ• ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ์—†์„๊นŒ?

" ๋ฐ”๋€” ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์„ ์ฐพ์•„๋‚ด์„œ ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ๋ถ€๋ถ„ํ•˜๊ณ  ๋ถ„๋ฆฌ์‹œ์ผœ์•ผ ํ•œ๋‹ค "

 

2) ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด๊ธฐ

๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” (new ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”) ๋ถ€๋ถ„์„ ๋ณ„๋„์˜ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ถ„๋ฆฌํ•˜์ž.

(1) PizzaStore

public class PizzaStore {

    SimplePizzaFactory factory;

    public PizzaStore(SimplePizzaFactory factory) {
        this.factory = factory;
    }

    public Pizza orderPizza(String type) {
        Pizza pizza;

        // ์–ด๋–ค ํ”ผ์ž ๋งŒ๋“ค์ง€ ๊ณต์žฅ์—์„œ (Factory) ์ƒ์„ฑ
        pizza = factory.createPizza(type);

        // ํ”ผ์ž ์กฐ๋ฆฌ
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}โ€‹

(2) ํŒฉํ† ๋ฆฌ (Factory) ์ƒ์„ฑ : SimplePizzaFactory

public class SimplePizzaFactory {
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        // ๊ฐ์ฒด์ƒ์„ฑ์„ ์บก์Šํ™”ํ•œ๋‹ค. ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๋Š” ๋ฐฉ์‹์ด๋‹ค.
        if (type.equals(PizzaType.CHEESE)) {
            pizza = new CheesePizza();
        } else if (type.equals(PizzaType.HAWAIIAN)) {
            pizza = new HawaiianPizza();
        } else if (type.equals(PizzaType.PEPPERONI)) {
            pizza = new PepperoniPizza();
        } else if (type.equals(PizzaType.VEGGIE)) {
            pizza = new VeggiePizza();
        }
        return pizza;
    }
}
public class PizzaType {
    public static final String CHEESE = "cheese";
    public static final String HAWAIIAN = "hawaiian";
    public static final String PEPPERONI = "pepperoni";
    public static final String VEGGIE = "veggie";
}

(3) Pizza ์ถ”์ƒ ํด๋ž˜์Šค

public abstract class Pizza {

    String name; // ํ”ผ์ž์ด๋ฆ„
    String dough; // ๋„์šฐ
    String sauce; // ์†Œ์Šค
    List<String> toppings = new ArrayList<>(); // ํ† ํ•‘

    public String getName() {
        return name;
    }

    public void prepare() {
        System.out.println("preparing... " + name);
    }

    public void bake() {
        System.out.println("baking... " + name);
    }

    public void cut() {
        System.out.println("cutting... " + name);
    }

    public void box() {
        System.out.println("boxing... " + name);
    }

    @Override
    public String toString() {
        // ํ”ผ์ž ์ •๋ณด ํ‘œ์‹œ
        StringBuilder sb = new StringBuilder();
        sb.append("===== " + name + " ํ”ผ์ž ์ •๋ณด =====\n");
        sb.append("dough = " + dough + "\n");
        sb.append("sauce = " + sauce + "\n");
        for (String topping : toppings) {
            sb.append("toppings = " + topping + "\n");
        }
        return sb.toString();
    }
}

(4) Pizza ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„

// ํŽ˜ํŽ˜๋กœ๋‹ˆ ํ”ผ์ž
public class PepperoniPizza extends Pizza {
    public PepperoniPizza() {
        name = "Pepperoni Pizza";
        dough = "Crust";
        sauce = "Marinara sauce";
        toppings.add("Sliced Pepperoni");
        toppings.add("Sliced Onion");
        toppings.add("Grated parmesan cheese");
    }
}
// ๊ทธ์™ธ ํ”ผ์ž๋“ค..

(5) ์‹คํ–‰

@Test
void simplePizza() {
    SimplePizzaFactory factory = new SimplePizzaFactory();
    PizzaStore pizzaStore = new PizzaStore(factory);
    pizza = pizzaStore.orderPizza(PizzaType.PEPPERONI);
    System.out.println(pizza.getName() + " ๋ฅผ ์ฃผ๋ฌธํ•ฉ๋‹ˆ๋‹ค.");
    System.out.println(pizza.toString());
}

(6) ๊ฒฐ๊ณผ ํ™•์ธ

preparing... Pepperoni Pizza
baking... Pepperoni Pizza
cutting... Pepperoni Pizza
boxing... Pepperoni Pizza
Pepperoni Pizza ๋ฅผ ์ฃผ๋ฌธํ•ฉ๋‹ˆ๋‹ค.
===== Pepperoni Pizza ํ”ผ์ž ์ •๋ณด =====
dough = Crust
sauce = Marinara sauce
toppings = Sliced Pepperoni
toppings = Sliced Onion
toppings = Grated parmesan cheese

๊ฐ„๋‹จํ•œ ํŒฉํ† ๋ฆฌ (Simple Factory) ๋Š” ์ด๋ ‡๊ฒŒ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ž‘์—…์„ ๋ถ„๋ฆฌํ•ด์„œ ์ด์šฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋””์ž์ธ ํŒจํ„ด์ด๋ผ๊ณ  ํ•  ์ˆ˜๋Š” ์—†๋‹ค. ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋Š”๋ฐ ์žˆ์–ด์„œ ์ž์ฃผ ์“ฐ์ด๋Š” ๊ด€์šฉ๊ตฌ์— ๊ฐ€๊น๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

3) ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค.

์ด ํ”ผ์ž๊ฐ€๊ฒŒ๊ฐ€ ์ธ๊ธฐ๊ฐ€ ์ƒ๊ฒจ ํ”„๋žœ์ฐจ์ด์ฆˆํ™” ๋˜์–ด ๋‹ค๋ฅธ ์ง€์—ญ์—๋„ ์ง€์ ์„ ๋‚ด๊ฒŒ๋๊ณ , ๊ฐ ์ง€์—ญ๋ณ„๋กœ ๊ณ ์œ  ์Šคํƒ€์ผ์˜ ํ”ผ์ž๋ฅผ ๋งŒ๋“ค์–ด ํŒ”๊ฒŒ ๋˜์—ˆ๋‹ค. ๋ชจ๋“  ๋ถ„์ ์—์„œ PizzaStore ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

๊ฐ„๋‹จํ•œ ํŒฉํ† ๋ฆฌ (Simple Factory) ๋ฅผ ์ด์šฉํ•ด์„œ ๋งŒ๋“ค์–ด๋ณด์ž.

// SimplePizzaFactory๋ฅผ ๋นผ๊ณ  ๊ฐ๊ฐ์˜ ์ง€์ ๋ณ„ ํŒฉํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค.
PizzaStore seoulStore = new PizzaStore(new SeoulPizzaFactory());
seoulStore.orderPizza("cheese");

PizzaStore busanStore = new PizzaStore(new BusanPizzaFactory());
busanStore.orderPizza("cheese");

PizzaStore suwonStore = new PizzaStore(new SuwonPizzaFactory());
suwonStore.orderPizza("cheese");

์œ„์™€ ๊ฐ™์€ ๊ตฌํ˜„์œผ๋กœ ๊ฐ ํŒฉํ† ๋ฆฌ๋ฅผ ๊ฐ€์ง„ ๋ถ„์ ๋“ค์ด ๊ฐ์ž์˜ ๋ฐฉ์‹์œผ๋กœ ํ”ผ์ž๋ฅผ ๋งŒ๋“ค์–ด ํŒ” ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.  ์˜ˆ๋ฅผ๋“ค์–ด ํ”ผ์ž๋ฅผ ๊ตฝ๋Š” ๋ฐฉ์‹์ด๋‚˜ ์ปทํŒ…๋ฐฉ์‹์˜ ์ฐจ์ด ๋“ฑ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ๋Š” ์ง€์ ๋งˆ๋‹ค ํŒฉํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ์ง€์ ์ด ๋Š˜์–ด๋‚ ์ˆ˜๋ก ์ฝ”๋“œ๊ฐ€ ๋ฐฉ๋Œ€ํ•ด์ ธ๋ฒ„๋ฆฌ๋‹ˆ ๋‹น์—ฐํžˆ ์ข‹์€ ๋ฐฉ๋ฒ•์ด ๋  ์ˆ˜ ์—†๋‹ค.

ํ”ผ์ž ์ œ์ž‘ํ™œ๋™์€ ๋ชจ๋‘ PizzaStore ํด๋ž˜์Šค์— ์œ„์ž„ํ•˜๋ฉด์„œ๋„ ๊ณ ์œ ์˜ ์Šคํƒ€์ผ์„ ์‚ด๋ฆด ์ˆ˜ ์žˆ๋„๋ก ํ”ผ์ž๊ฐ€๊ฒŒ (PizzaStore) ์™€ ์ œ์ž‘๊ณผ์ • ( prepare() → bake() → cut() → box() ) ์„ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด์ฃผ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์ƒ๊ฒผ๋‹ค.

 

2. ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ ํŒจํ„ด

(1) ํ”ผ์ž๊ฐ€๊ฒŒ PizzaStore ์ถ”์ƒ ํด๋ž˜์Šค : ํ”ผ์ž ์ œ์ž‘ํ™œ๋™์„ ๋ชจ๋‘ ์œ„์ž„ํ•˜๋ฉด์„œ๋„ ๊ณ ์œ ์Šคํƒ€์ผ์€ ํŒฉํ† ๋ฆฌ์—์„œ ํ•ด๊ฒฐํ•˜๋„๋กํ•œ๋‹ค.

public abstract class PizzaStore {
    // Pizza ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ์ผ์€ ํŒฉํ† ๋ฆฌ ์—ญํ• ์„ ํ•˜๋Š” ์ธ์Šคํ„ด์Šค์—์„œ
    public abstract Pizza createPizza(String item);

    public Pizza orderPizza(String type) { // ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ์—์˜ํ•ด ์ƒ์‚ฐ๋œ ์ œํ’ˆ๊ฐ€์ง€๊ณ  ์ž‘์—…์ฒ˜๋ฆฌ
        Pizza pizza = createPizza(type); // ์‹ค์ œ ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ ๊ตฌํ˜„์€ ์ œํ’ˆ ๋งŒ๋“œ๋Š” ์„œ๋ธŒํด๋ž˜์Šค์—์„œ
        System.out.println("==== " + pizza.getName() + " ์ œ์ž‘ ====");
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
}

(2) PizzaStore ๋ฅผ ์ƒ์†ํ•ด์„œ ๊ฐ ์ง€์  ํ”ผ์ž๊ฐ€๊ฒŒ ์„œ๋ธŒ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๊ณ  ์ง€์ ์—์„œ ์Šคํƒ€์ผ์„ ๊ฒฐ์ •ํ•˜๋„๋ก ํ•œ๋‹ค.

// ์„œ์šธ ํ”ผ์ž ์ง€์ 
public class SeoulPizzaStore extends PizzaStore {
    @Override
    public Pizza createPizza(String type) {
        if (type.equals(PizzaType.CHEESE)) {
            return new SeoulStyleCheesePizza();
        } else if (type.equals(PizzaType.HAWAIIAN)) {
            return new SeoulStyleHawaiianPizza();
        } else if (type.equals(PizzaType.PEPPERONI)) {
            return new SeoulStylePepperoniPizza();
        } else if (type.equals(PizzaType.VEGGIE)) {
            return new SeoulStyleVeggiePizza();
        } else {
            return null;
        }
    }
}
// ๋ถ€์‚ฐ์ง€์ 
public class BusanPizzaStore extends PizzaStore {
    @Override
    public Pizza createPizza(String type) {
        if (type.equals(PizzaType.CHEESE)) {
            return new BusanStyleCheesePizza();
        } else if (type.equals(PizzaType.HAWAIIAN)) {
            return new BusanStyleHawaiianPizza();
        } else if (type.equals(PizzaType.PEPPERONI)) {
            return new BusanStylePepperoniPizza();
        } else if (type.equals(PizzaType.VEGGIE)) {
            return new BusanStyleVeggiePizza();
        } else {
            return null;
        }
    }
}

๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๊ฐ–๋Š”๋‹ค.

(3)  Pizza ํด๋ž˜์Šค

public abstract class Pizza {

    String name; // ํ”ผ์ž์ด๋ฆ„
    String dough; // ๋„์šฐ
    String sauce; // ์†Œ์Šค
    List<String> toppings = new ArrayList<>();  // ํ† ํ•‘

    public void prepare() {
        System.out.println("preparing... " + name);
        System.out.println("tossing dough...");
        System.out.println("adding sauce...");
        System.out.println("adding toppings...");
        for (String topping : toppings) {
            System.out.println("    " + topping);
        }
    }

    public void bake() {
        System.out.println("baking... 350๋„์—์„œ 25๋ถ„์ •๋„ ๊ตฌ์›๋‹ˆ๋‹ค.");
    }

    public void cut() {
        System.out.println("cutting... ํ”ผ์ž๋ฅผ ์ปคํŒ…ํ•ฉ๋‹ˆ๋‹ค.");
    }

    public void box() {
        System.out.println("boxing... ๋ฐ•์Šค์— ๋„ฃ์Šต๋‹ˆ๋‹ค.");
    }

    public String getName() { return name; }

    @Override
    public String toString() {  // ํ”ผ์ž ์ •๋ณด ํ‘œ์‹œ
        StringBuilder sb = new StringBuilder();
        sb.append("===== " + name + " =====\n");
        sb.append("dough = " + dough + "\n");
        sb.append("sauce = " + sauce + "\n");
        for (String topping : toppings) {
            sb.append("toppings = " + topping + "\n");
        }
        return sb.toString();
    }
}

(4)  Pizza ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์•„ ๊ฐ ์ง€์ ๋ณ„ ๊ณ ์œ  ์Šคํƒ€์ผ ํ”ผ์ž ๊ตฌํ˜„

// ์„œ์šธ ์Šคํƒ€์ผ ํ•˜์™€์ด์•ˆ ํ”ผ์ž
public class SeoulStyleHawaiianPizza extends Pizza {
    public SeoulStyleHawaiianPizza() {
        name = "Seoul Style Hawaiian Pizza";
        dough = "Thin Crust";
        sauce = "Marinara Sauce";
        toppings.add("Pineapple");
        toppings.add("Pepperoni");
        toppings.add("Italian Sausage");
    }
}
// ๋ถ€์‚ฐ ์Šคํƒ€์ผ ํŽ˜ํŽ˜๋กœ๋‹ˆ ํ”ผ์ž
public class BusanStylePepperoniPizza extends Pizza {
    public BusanStylePepperoniPizza() {
        name = "Busan Style Pepperoni Pizza";
        dough = "Crust";
        sauce = "Marinara sauce";
        toppings.add("Sliced Double Pepperoni");
        toppings.add("Grated parmesan cheese");
    }

    @Override
    public void cut() { // ์ œ์ž‘๊ณผ์ •๋„ ๊ฐ ์Šคํƒ€์ผ์— ๋งž๊ฒŒ ๊ตฌํ˜„๊ฐ€๋Šฅ
        System.out.println("cutting.. square cut!");
    }
}

(5)  ์‹คํ–‰

@Test
void simpleExtend() {
    // ๊ฐ์ฒด ์ƒ์„ฑ์„ ์บก์Šํ™”        
    PizzaStore seoulStore = new SeoulPizzaStore();
    PizzaStore busanStore = new BusanPizzaStore();
    
    System.out.println("์„œ์šธ์ง€์  1๋ฒˆ ์†๋‹˜ ์ฃผ๋ฌธ");
    Pizza fistPizza = seoulStore.orderPizza(PizzaType.HAWAIIAN);
    System.out.println("๋ถ€์‚ฐ์ง€์  2๋ฒˆ ์†๋‹˜ ์ฃผ๋ฌธ");
    Pizza secondPizza = busanStore.orderPizza(PizzaType.PEPPERONI);
}

(6) ์ถœ๋ ฅ๊ฒฐ๊ณผ ํ™•์ธ

์„œ์šธ์ง€์  1๋ฒˆ ์†๋‹˜ ์ฃผ๋ฌธ
==== Seoul Style Hawaiian Pizza ์ œ์ž‘ ====
preparing... Seoul Style Hawaiian Pizza
tossing dough...
adding sauce...
adding toppings...
    Pineapple
    Pepperoni
    Italian Sausage
baking... 350๋„์—์„œ 25๋ถ„์ •๋„ ๊ตฌ์›๋‹ˆ๋‹ค.
cutting... ํ”ผ์ž๋ฅผ ์ปคํŒ…ํ•ฉ๋‹ˆ๋‹ค.
boxing... ๋ฐ•์Šค์— ๋„ฃ์Šต๋‹ˆ๋‹ค.

๋ถ€์‚ฐ์ง€์  2๋ฒˆ ์†๋‹˜ ์ฃผ๋ฌธ
==== Busan Style Pepperoni Pizza ์ œ์ž‘ ====
preparing... Busan Style Pepperoni Pizza
tossing dough...
adding sauce...
adding toppings...
    Sliced Double Pepperoni
    Grated parmesan cheese
baking... 350๋„์—์„œ 25๋ถ„์ •๋„ ๊ตฌ์›๋‹ˆ๋‹ค.
cutting.. square cut!
boxing... ๋ฐ•์Šค์— ๋„ฃ์Šต๋‹ˆ๋‹ค.

๊ฐ ์ง€์  ์Šคํƒ€์ผ์— ๋งž๊ฒŒ ์ œ์ž‘๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

โ‘  ์ƒ์‚ฐ์ž ํด๋ž˜์Šค PizzaStore : ๊ฐ์ฒด๋ฅผ ์ƒ์‚ฐ

โ‘ก ์ œํ’ˆ ํด๋ž˜์Šค Pizza : ์ œํ’ˆ์„ ์ƒ์‚ฐ

XxxStyleXxxPizza : ๊ฐ ์ง€์ ๋ณ„ ํ”ผ์ž ๊ฐ์ฒด๊ฐ€ ์กด์žฌํ•œ๋‹ค.

์ƒ์‚ฐ์„ ๋‹ด๋‹นํ•˜๋Š” PizzaStore ์ถ”์ƒ ํด๋ž˜์Šค์—์„œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ธฐ์œ„ํ•œ ๋ฉ”์†Œ๋“œ createPizza() ๋ฅผ ์ œ๊ณตํ•ด์ค€๋‹ค. ์ฆ‰, ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

PizzaStore ์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ๋‹ค๋ฅธ ๋ฉ”์†Œ๋“œ orderPizza() ์—์„œ๋Š” ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ์— ์˜ํ•ด ์ƒ์‚ฐ๋œ ์ œํ’ˆ์„ ๊ฐ€์ง€๊ณ  ํ•„์š”ํ•œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์‹ค์ œ ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์ œํ’ˆ (๊ฐ์ฒด ์ธ์Šคํ„ด์Šค) ์„ ๋งŒ๋“ค์–ด ๋‚ด๋Š” ์ผ์€ ์„œ๋ธŒํด๋ž˜์Šค์—์„œ๋งŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

concrete class ์— ๋Œ€ํ•œ ์˜์กด์„ฑ์„ ์ค„์ด๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

โ–  ์˜์กด์„ฑ ๋’ค์ง‘๊ธฐ ์›์น™

๐Ÿ“Œ ๋””์ž์ธ ์›์น™
    ์˜์กด์„ฑ ๋’ค์ง‘๊ธฐ ์›์น™ (Dependency Inversion Principle)
    ์ถ”์ƒํ™”๋œ ๊ฒƒ์— ์˜์กดํ•˜๋„๋ก ๋งŒ๋“ค์–ด๋ผ. ๊ตฌ์ƒ ํด๋ž˜์Šค (concrete class) ์— ์˜์กดํ•˜๋„๋ก ๋งŒ๋“ค์ง€ ์•Š๋„๋ก ํ•œ๋‹ค.

 

 

  • PizzaStore : ์ถ”์ƒ ํด๋ž˜์Šค (abstract class)
    Pizza ํด๋ž˜์Šค์—๋งŒ ์˜์กดํ•œ๋‹ค.
  • Pizza : ์ถ”์ƒ ํด๋ž˜์Šค (abstract class)
  • XxxStyleXxxPizza : ๊ตฌ์ƒ ํด๋ž˜์Šค (Concrete class)
    ๊ฐ ๊ตฌ์ƒ ํด๋ž˜์Šค ์—ญ์‹œ Pizza ์ถ”์ƒ ํด๋ž˜์Šค์— ์˜์กดํ•œ๋‹ค.
    Pizza ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

 

 

 

 

 

 

 

 

์™œ '์˜์กด์„ฑ ๋’ค์ง‘๊ธฐ ์›์น™'์ธ๊ฐ€?

ใ€์ ์šฉ ์ „ใ€‘ ใ€์ ์šฉ ํ›„ใ€‘
PizzaStore → SeoulStyleCheesePizza
PizzaStore → BusanStylePepperoniPizza
PizzaStore → Pizza
Pizza ← SeoulStyleCheesePizza
Pizza ← BusanStylePepperoniPizza

์œ„์™€ ๊ฐ™์ด ์˜์กด๊ด€๊ณ„๊ฐ€ ๋’ค์ง‘์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์˜์กด์„ฑ ๋’ค์ง‘๊ธฐ ์›์น™์ด๋ผ ํ•œ๋‹ค.

ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ ํŒจํ„ด์„ ์ ์šฉํ•˜๊ณ  ๋‚˜๋ฉด ๊ณ ์ˆ˜์ค€ ๊ตฌ์„ฑ์š”์†Œ (PizzaStore) ์™€ ์ €์ˆ˜์ค€ ๊ตฌ์„ฑ์š”์†Œ(SeoulStyleCheesePizza, BusanStylePepperoniPizza, ...) ๋“ค์ด ๋ชจ๋‘ ์ถ”์ƒํด๋ž˜์Šค Pizza ์— ์˜์กดํ•˜๊ฒŒ ๋œ๋‹ค. (๊ณ ์ˆ˜์ค€ ๋ชจ๋“ˆ๊ณผ ์ €์ˆ˜์ค€ ๋ชจ๋“ˆ์ด ๋ชจ๋‘ ํ•˜๋‚˜์˜ ์ถ”์ƒ ํด๋ž˜์Šค์— ์˜์กดํ•œ๋‹ค.)

์ฐธ๊ณ ๋กœ ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ ํŒจํ„ด์ด ์˜์กด์„ฑ ๋’ค์ง‘๊ธฐ ์›์น™์„ ์ค€์ˆ˜ํ•˜๊ธฐ ์œ„ํ•ด ์“ฐ๋Š” ์œ ์ผํ•œ ๊ธฐ๋ฒ•์€ ์•„๋‹ˆ๋‹ค.

๐Ÿ”‘ ์˜์กด์„ฑ ๋’ค์ง‘๊ธฐ ์›์น™์— ์œ„๋ฐฐ๋˜๋Š” ๊ฐ์ฒด์ง€ํ–ฅ ๋””์ž์ธ์„ ํ”ผํ•˜๋Š”๋ฐ ๋„์›€์ด ๋˜๋Š” ๊ฐ€์ด๋“œ
1. ์–ด๋–ค ๋ณ€์ˆ˜์—๋„ ๊ตฌ์ƒ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค.
    new ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.
2. ๊ตฌ์ƒ ํด๋ž˜์Šค์—์„œ ์œ ๋„๋œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.
    ๊ตฌ์ƒ ํด๋ž˜์Šค์—์„œ ์œ ๋„๋œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋ฉด ํŠน์ • ๊ตฌ์ƒ ํด๋ž˜์Šค์— ์˜์กดํ•˜๊ฒŒ ๋œ๋‹ค.
    ์ถ”์ƒํ™” ๋œ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.
3. ๋ฒ ์ด์Šค ํด๋ž˜์Šค์— ์ด๋ฏธ ๊ตฌํ˜„๋˜์–ด ์žˆ๋˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•˜์ง€ ์•Š๋Š”๋‹ค.
    ์ด๋ฏธ ๊ตฌํ˜„๋œ ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์• ์ดˆ๋ถ€ํ„ฐ ๋ฒ ์ด์Šค ํด๋ž˜์Šค๊ฐ€ ์ œ๋Œ€๋กœ ์ถ”์ƒํ™”๋˜์ง€ ์•Š์€ ๊ฒƒ์ด๋‹ค.
    ๋ฒ ์ด์Šค ํด๋ž˜์Šค์—์„œ ๋ฉ”์†Œ๋“œ๋ฅผ ์ •์˜ํ•  ๋•Œ๋Š” ๋ชจ๋“  ์„œ๋ธŒ ํด๋ž˜์Šค์—์„œ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋งŒ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.

์ •๋ฆฌํ•˜๋ฉด ๋งŒ๋“ค๊ณ  ์žˆ๋Š” ํด๋ž˜์Šค๊ฐ€ ๋ฐ”๋€” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๋ฉด ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ ํŒจํ„ด ๊ฐ™์€ ๊ธฐ๋ฒ•์„ ์จ์„œ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์„ ์บก์Šํ™” ํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

 

3. ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด

๋””์ž์ธ ์›์น™๋„ ์ง€์ผœ๊ฐ€๋ฉด์„œ ์œ ์—ฐํ•œ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๋งŒ๋“ค์—ˆ๋‹ค. ๊ฐ ์ง€์ ๋“ค์ด ์ž˜ ์šด์˜๋˜๋Š” ๊ฒƒ ๊ฐ™์•˜๋‹ค. ๊ทธ๋Ÿฐ๋ฐ, ๋ช‡๋ช‡ ์ง€์ ๋“ค์ด ์žฌ๋ฃŒ๋ฅผ ๋” ์‹ผ ๊ฒƒ์œผ๋กœ ๋ฐ”๊ฟ”์„œ ์›๊ฐ€๋ฅผ ์ ˆ๊ฐํ•ด ๋งˆ์ง„์„ ๋‚จ๊ธฐ๊ณ  ์žˆ์—ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์›์žฌ๋ฃŒ์˜ ํ’ˆ์งˆ๊นŒ์ง€ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ด์กŒ๋‹ค.

์›์žฌ๋ฃŒ ๊ตฐ์„ ๋งŒ๋“ค์–ด ํŒŒ์•…ํ•ด๋ณด์ž. ์ œํ’ˆ์— ๋“ค์–ด๊ฐ€๋Š” ์žฌ๋ฃŒ๊ตฐ (๋ฐ˜์ฃฝ, ์†Œ์Šค, ์น˜์ฆˆ, ์•ผ์ฑ„, ๊ณ ๊ธฐ ๋“ฑ) ์€ ๊ฐ™์ง€๋งŒ, ์ง€์—ญ๋งˆ๋‹ค ์žฌ๋ฃŒ์˜ ๊ตฌ์ฒด์ ์ธ ํŠน์ง•์ด ์กฐ๊ธˆ์”ฉ ๋‹ฌ๋ž๋‹ค.

 

(1) ์›์žฌ๋ฃŒ

๋Œ€ํ‘œ์ ์œผ๋กœ Cheese, Dough, Sauce, Pepperoni, Fruits, Veggies ๋กœ ๊ตฌ๋ถ„ํ•˜๊ณ  ๊ฐ ์ƒ์„ธ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.

// Cheese ์˜ ๊ฒฝ์šฐ
public interface Cheese {
    String toString();
}
public class MozzarellaCheese implements Cheese { // ๊ฐ Cheese ๊ตฌํ˜„
    public String toString() { return "mozzarella cheese"; }
}
// Dough ์˜ ๊ฒฝ์šฐ
public interface Dough {
    String toString();
}
public class ThinCrustDough implements Dough { // ๊ฐ Dough ๊ตฌํ˜„
    public String toString() { return "thin crust dough"; }
}
// Sauce, Veggies, Pepperoni, Fruits .. ์ดํ•˜์ƒ๋žต

(2) ์›์žฌ๋ฃŒ ๊ณต์žฅ์„ ๋งŒ๋“ค์ž.

โ‘  ์ง€์—ญ๋ณ„๋กœ ๊ณต์žฅ (factory) ์„ ๋งŒ๋“ค์–ด ๊ฐ ์ƒ์„ฑ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” PizzaIngredientFactory ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ž.

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

โ‘ก ๊ฐ ์ง€์ ์˜ ์›์žฌ๋ฃŒ ๊ณต์žฅ (factory) ๋ฅผ ๊ตฌํ˜„

// ์„œ์šธ ์ง€์  ์›์žฌ๋ฃŒ ๊ณต์žฅ
public class SeoulIngredientFactory implements PizzaIngredientFactory {

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

    @Override
    public Cheese createCheese() {
        return new ParmesanCheese();
    }

    @Override
    public Fruits createFruits() {
        return new Pineapple();
    }

    @Override
    public Pepperoni createPepperoni() {
        return new SlicedPepperoni();
    }

    @Override
    public Veggies[] createVeggies() {
        Veggies[] veggies = {new Garlic(), new Spinach(), new BlackOlives()};
        return veggies;
    }

    @Override
    public Sauce createSauce() {
        return new TomatoSauce();
    }
}
// ๋ถ€์‚ฐ ์ง€์  ์›์žฌ๋ฃŒ ๊ณต์žฅ
public class BusanIngredientFactory implements PizzaIngredientFactory {

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

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }

    @Override
    public Fruits createFruits() {
        return new Pineapple();
    }

    @Override
    public Pepperoni createPepperoni() {
        return new SlicedPepperoni();
    }

    @Override
    public Veggies[] createVeggies() {
        Veggies[] veggies = {new Onion(), new Spinach(), new Mushroom()};
        return veggies;
    }

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

(3) ํ”ผ์ž ์ถ”์ƒ ํด๋ž˜์Šค, ๊ฐ ํ”ผ์ž ๊ตฌํ˜„

// ํ”ผ์ž ์ถ”์ƒ ํด๋ž˜์Šค
public abstract class Pizza {
    public String name; // ํ”ผ์ž์ด๋ฆ„
    public Dough dough; // ๋„์šฐ
    public Cheese cheese; // ์น˜์ฆˆ
    public Fruits fruits; // ๊ณผ์ผ
    public Pepperoni pepperoni; // ํŽ˜ํŽ˜๋กœ๋‹ˆ
    public Sauce sauce; // ์†Œ์Šค
    public Veggies[] veggies; // ์•ผ์ฑ„๋“ค

    public abstract void prepare(); // point : ์ถ”์ƒ๋ฉ”์†Œ๋“œ๋กœ ๋ณ€๊ฒฝ๋จ!!

    public void bake() {
        System.out.println("baking... 350 ๋„์—์„œ 25๋ถ„");
    }

    public void box() {
        System.out.println("boxing... ๋ฐ•์Šค์— ํฌ์žฅ");
    }

    public void cut() {
        System.out.println("cutting... ์ปคํŒ…");
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("===== " + name + " =====\n");
        if (dough != null) {
            sb.append(dough);
            sb.append("\n");
        }
        if (sauce != null) {
            sb.append(sauce);
            sb.append("\n");
        }
        if (cheese != null) {
            sb.append(cheese);
            sb.append("\n");
        }
        if (pepperoni != null) {
            sb.append(pepperoni);
            sb.append("\n");
        }
        if (fruits != null) {
            sb.append(fruits);
            sb.append("\n");
        }
        if (veggies != null) {
            for (Veggies veg : veggies) {
                sb.append(veg);
                sb.append(", ");
            }
                sb.append("\n");
        }
        return sb.toString();
    }
}
// ๊ฐ ํ”ผ์ž ๊ตฌํ˜„
public class PepperoniPizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;

    public PepperoniPizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }

    @Override
    public void prepare() {
        System.out.println("preparing... " + name);
        dough = ingredientFactory.createDough();
        pepperoni = ingredientFactory.createPepperoni();
        cheese = ingredientFactory.createCheese();
        sauce = ingredientFactory.createSauce();
        veggies = ingredientFactory.createVeggies();
    }
}
// ๋ถ€์‚ฐ์Šคํƒ€์ผ ํŽ˜ํŽ˜๋กœ๋‹ˆ ํ”ผ์ž ๊ตฌํ˜„
public class BusanStylePepperoniPizza extends Pizza {
    PizzaIngredientFactory ingredientFactory;

    public BusanStylePepperoniPizza(PizzaIngredientFactory ingredientFactory) {
        this.ingredientFactory = ingredientFactory;
    }

    @Override
    public void prepare() {
        System.out.println("preparing... " + name);
        dough = ingredientFactory.createDough();
        pepperoni = ingredientFactory.createPepperoni();
        cheese = ingredientFactory.createCheese();
        sauce = ingredientFactory.createSauce();
        veggies = ingredientFactory.createVeggies();
    }

    @Override
    public void box() {
        System.out.println("๋ถ€์‚ฐ ์ด๋ฒคํŠธ ๋ฐ•์Šค์— ๋„ฃ์Šต๋‹ˆ๋‹ค.");
    }
}

(4) ๋งŒ๋“  ์›์žฌ๋ฃŒ ๊ณต์žฅ์„ PizzaStore ์—์„œ ์‚ฌ์šฉํ•˜๋„๋ก ํ•จ์œผ๋กœ์จ ํ•˜๋‚˜๋กœ ๋ฌถ์ž

// ์„œ์šธ์ง€์ 
public class SeoulPizzaStore extends PizzaStore {

    @Override
    protected Pizza createPizza(String item) {
        Pizza pizza = null;
        // ์›์žฌ๋ฃŒ ๊ณต์žฅ
        PizzaIngredientFactory ingredientFactory = new SeoulIngredientFactory();

        if (item.equals(PizzaType.PEPPERONI)) {
            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("์„œ์šธ ์Šคํƒ€์ผ ํŽ˜ํŽ˜๋กœ๋‹ˆ ํ”ผ์ž");
        } else if (item.equals(PizzaType.HAWAIIAN)) {
            pizza = new HawaiianPizza(ingredientFactory);
            pizza.setName("์„œ์šธ ์Šคํƒ€์ผ ํ•˜์™€์ด์•ˆ ํ”ผ์ž");
        } else if (item.equals(PizzaType.VEGGIE)) {
            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("์„œ์šธ ์Šคํƒ€์ผ ๋ฒ ์ง€ํ…Œ๋ฆฌ์•ˆ ํ”ผ์ž");
        }
        return pizza;
    }
}
// ๋ถ€์‚ฐ์ง€์ 
public class BusanPizzaStore extends PizzaStore {

    @Override
    protected Pizza createPizza(String item) {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new BusanIngredientFactory();

        if (item.equals(PizzaType.PEPPERONI)) {
            pizza = new BusanStylePepperoniPizza(ingredientFactory);
            pizza.setName("๋ถ€์‚ฐ ์Šคํƒ€์ผ ํŽ˜ํŽ˜๋กœ๋‹ˆ ํ”ผ์ž");
        } else if (item.equals(PizzaType.HAWAIIAN)) {
            pizza = new HawaiianPizza(ingredientFactory);
            pizza.setName("๋ถ€์‚ฐ ์Šคํƒ€์ผ ํ•˜์™€์ด์•ˆ ํ”ผ์ž");
        } else if (item.equals(PizzaType.VEGGIE)) {
            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("๋ถ€์‚ฐ ์Šคํƒ€์ผ ๋ฒ ์ง€ํ…Œ๋ฆฌ์•ˆ ํ”ผ์ž");
        }
        return pizza;
    }
}

(5) ์‹คํ–‰

@Test
void abstractFactoryTest() {
    PizzaStore seoulStore = new SeoulPizzaStore(); // ์„œ์šธ์ง€์  ์ƒ์„ฑ
    PizzaStore busanStore = new BusanPizzaStore(); // ๋ถ€์‚ฐ์ง€์  ์ƒ์„ฑ
    
    System.out.println("์„œ์šธ ํ”ผ์ž ์ฃผ๋ฌธ 1");
    Pizza seoul1 = seoulStore.orderPizza(PizzaType.PEPPERONI); // ์„œ์šธ์ง€์  ์ฃผ๋ฌธ1
    System.out.println("์„œ์šธ ํ”ผ์ž ์ฃผ๋ฌธ 2");
    Pizza seoul2 = seoulStore.orderPizza(PizzaType.VEGGIE); // ์„œ์šธ์ง€์  ์ฃผ๋ฌธ2
    System.out.println("๋ถ€์‚ฐ ํ”ผ์ž ์ฃผ๋ฌธ 1");
    Pizza busan1 = busanStore.orderPizza(PizzaType.PEPPERONI); // ๋ถ€์‚ฐ์ง€์  ์ฃผ๋ฌธ1
    System.out.println("๋ถ€์‚ฐ ํ”ผ์ž ์ฃผ๋ฌธ 2");
    Pizza busan2 = busanStore.orderPizza(PizzaType.VEGGIE); // ๋ถ€์‚ฐ์ง€์  ์ฃผ๋ฌธ2
}

(6) ๊ฒฐ๊ณผํ™•์ธ

์„œ์šธ ํ”ผ์ž ์ฃผ๋ฌธ 1
===== ์„œ์šธ ์Šคํƒ€์ผ ํŽ˜ํŽ˜๋กœ๋‹ˆ ํ”ผ์ž ์ œ์ž‘ =====
preparing... ์„œ์šธ ์Šคํƒ€์ผ ํŽ˜ํŽ˜๋กœ๋‹ˆ ํ”ผ์ž
baking... 350 ๋„์—์„œ 25๋ถ„
cutting... ์ปคํŒ…
boxing... ๋ฐ•์Šค์— ํฌ์žฅ

์„œ์šธ ํ”ผ์ž ์ฃผ๋ฌธ 2
===== ์„œ์šธ ์Šคํƒ€์ผ ๋ฒ ์ง€ํ…Œ๋ฆฌ์•ˆ ํ”ผ์ž ์ œ์ž‘ =====
preparing... ์„œ์šธ ์Šคํƒ€์ผ ๋ฒ ์ง€ํ…Œ๋ฆฌ์•ˆ ํ”ผ์ž
baking... 350 ๋„์—์„œ 25๋ถ„
cutting... ์ปคํŒ…
boxing... ๋ฐ•์Šค์— ํฌ์žฅ

๋ถ€์‚ฐ ํ”ผ์ž ์ฃผ๋ฌธ 1
===== ๋ถ€์‚ฐ ์Šคํƒ€์ผ ํŽ˜ํŽ˜๋กœ๋‹ˆ ํ”ผ์ž ์ œ์ž‘ =====
preparing... ๋ถ€์‚ฐ ์Šคํƒ€์ผ ํŽ˜ํŽ˜๋กœ๋‹ˆ ํ”ผ์ž
baking... 350 ๋„์—์„œ 25๋ถ„
cutting... ์ปคํŒ…
๋ถ€์‚ฐ ์ด๋ฒคํŠธ ๋ฐ•์Šค์— ๋„ฃ์Šต๋‹ˆ๋‹ค.

๋ถ€์‚ฐ ํ”ผ์ž ์ฃผ๋ฌธ 2
===== ๋ถ€์‚ฐ ์Šคํƒ€์ผ ๋ฒ ์ง€ํ…Œ๋ฆฌ์•ˆ ํ”ผ์ž ์ œ์ž‘ =====
preparing... ๋ถ€์‚ฐ ์Šคํƒ€์ผ ๋ฒ ์ง€ํ…Œ๋ฆฌ์•ˆ ํ”ผ์ž
baking... 350 ๋„์—์„œ 25๋ถ„
cutting... ์ปคํŒ…
boxing... ๋ฐ•์Šค์— ํฌ์žฅ

4. ์ •๋ฆฌํ•˜๋ฉด

๐Ÿ“Œ ์ถ”์ƒ ํŒฉํ† ๋ฆฌ ํŒจํ„ด 
์ œํ’ˆ๊ตฐ์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑ ๊ทธ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ• ์ˆ˜ ์žˆ๊ฒŒ๋” ํ•˜๋Š”๊ฒƒ
๐Ÿ“Œ ์ถ”์ƒ ๋ฉ”์†Œ๋“œ ํŒจํ„ด 
ํ•˜๋‚˜์˜ ์ถ”์ƒํด๋ž˜์Šค์—์„œ ์ถ”์ƒ ๋ฉ”์†Œ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  ์„œ๋ธŒํด๋ž˜์Šค๋“ค์ด ๊ทธ ์ถ”์ƒ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ ํ•˜์—ฌ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ฒŒ๋” ํ•˜๋Š”๊ฒƒ

 

 

 

 


์ฐธ๊ณ 
ํ—ค๋“œ ํผ์ŠคํŠธ ๋””์ž์ธ ํŒจํ„ด (Head First Design Patterns) - ์—๋ฆญ ํ”„๋ฆฌ๋จผ,์—˜๋ฆฌ์ž๋ฒ ์Šค ๋กญ์Šจ,์ผ€์ด์‹œ ์‹œ์—๋ผ,๋ฒ„ํŠธ ๋ฒ ์ด์ธ 

 

 

 

 

๋ฐ˜์‘ํ˜•