디자인패턴

Abstract Factory Pattern

hik14 2022. 8. 1. 15:56

추상 팩토리 패턴 

특정한 제품군을 생성할때 사용한다.

구상 클래스에 의존하지 않고도 서로 연관되거나 의존적인 객체로 이루어진 제품군을 생산하는 인터페이스를 제공합니다. 

 

 

 

추상 팩토리 인터페스 및 구상 클래스.

interface PizzaIngredientFactory {
    fun createDough(): Dough
    fun createSauce(): Sauce
    fun createCheese(): Cheese
    fun createPepperoni(): Pepperoni
}

class NYPizzaIngredientFactory : PizzaIngredientFactory {

    override fun createDough(): Dough = ThinCrustDough()

    override fun createSauce(): Sauce = MarinaraSauce()

    override fun createCheese(): Cheese = ReggianoCheese()

    override fun createPepperoni(): Pepperoni = ThickPepperoni()
}

class ChicagoPizzaIngredientFactory : PizzaIngredientFactory {

    override fun createDough(): Dough = ThickCrustDough()

    override fun createSauce(): Sauce = PlumTomatoSauce()

    override fun createCheese(): Cheese = MozzarellaCheese()

    override fun createPepperoni(): Pepperoni = SlicedPepperoni()
}

 

원재료 인터페이스 및 클래스

interface Dough

class ThickCrustDough : Dough {
    init {
        println("두꺼운 크러스트 도우")
    }
}

class ThinCrustDough : Dough {
    init {
        println("얇은 크러스트 도우")
    }
}

interface Sauce

class PlumTomatoSauce : Sauce {
    init {
        println("플럼 토마토 소스")
    }
}

class MarinaraSauce : Sauce {
    init {
        println("마리아라 소스")
    }
}

interface Cheese

class MozzarellaCheese : Cheese {
    init {
        println("모짜랄레 치즈")
    }
}

class ReggianoCheese : Cheese {
    init {
        println("레기아노치즈")
    }
}

interface Pepperoni

class SlicedPepperoni : Pepperoni {
    init {
        println("얇게 썰린 페퍼로니")
    }
}

class ThickPepperoni : Pepperoni {
    init {
        println("통 페퍼로니")
    }
}

기존의 클래스들 prepare()를 추상클래스로 변경한다. 

각 피자에 맞도록 제품군을 원재료 클래스에서 생성한다.

enum class PizzaType {
    CHEESE, PEPPERONI
}

abstract class Pizza(val ingredientFactory: PizzaIngredientFactory) {

    abstract val name: String
    lateinit var dough: Dough
    lateinit var sauce: Sauce
    lateinit var cheese: Cheese
    lateinit var pepperoni: Pepperoni

    abstract fun prepare()

    fun bake() {
        println("175도에서 25분간 굽기")
    }

    open fun cut() {
        println("피자를 사선으로 자르기")
    }

    fun box() {
        println("상자에 피자 담기")
    }
}

class NYStyleCheesePizza(ingredientFactory: PizzaIngredientFactory) : Pizza(ingredientFactory) {

    override val name: String = "뉴욕 스타일 치즈 피자"

    override fun prepare() {
        println("준비중: $name")
        dough = ingredientFactory.createDough()
        sauce = ingredientFactory.createSauce()
        cheese = ingredientFactory.createCheese()
    }

}

class NYStylePepperoniPizza(ingredientFactory: PizzaIngredientFactory) : Pizza(ingredientFactory) {

    override val name: String = "뉴욕 스타일 페퍼로니 피자"

    override fun prepare() {
        println("준비중: $name")
        dough = ingredientFactory.createDough()
        sauce = ingredientFactory.createSauce()
        pepperoni = ingredientFactory.createPepperoni()
    }
}

class ChicagoStyleCheesePizza(ingredientFactory: PizzaIngredientFactory) : Pizza(ingredientFactory) {

    override val name: String = "시카고 스타일 치즈 피자"

    override fun cut() {
        println("네모난 모양으로 피자 자르기")
    }

    override fun prepare() {
        println("준비중: $name")
        dough = ingredientFactory.createDough()
        sauce = ingredientFactory.createSauce()
        cheese = ingredientFactory.createCheese()
    }
}

class ChicagoStylePepperoniPizza(ingredientFactory: PizzaIngredientFactory) : Pizza(ingredientFactory) {

    override val name: String = "시카고 스타일 페퍼로니 피자"

    override fun cut() {
        println("네모난 모양으로 피자 자르기")
    }

    override fun prepare() {
        println("준비중: $name")
        dough = ingredientFactory.createDough()
        sauce = ingredientFactory.createSauce()
        pepperoni = ingredientFactory.createPepperoni()
    }
}

 

abstract class PizzaStore {

    // 어떤 피자던 주문하는 과정 및 포장 처리는 변함이 없다.
    fun orderPizza(type: PizzaType): Pizza {
        val pizza = createPizza(type)

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

        return pizza
    }
    // 피자의 종류에 따라 실제 어떤 피자를 생성하여 반환 할지는 하위 클래스에서 결정하기로 한다.
    protected abstract fun createPizza(type: PizzaType): Pizza
}

class NYPizzaStore : PizzaStore() {

    override fun createPizza(type: PizzaType): Pizza {
        val ingredientFactory = NYPizzaIngredientFactory()

       return when (type) {
            PizzaType.CHEESE -> {
                NYStyleCheesePizza(ingredientFactory)
            }
            PizzaType.PEPPERONI -> {
                NYStylePepperoniPizza(ingredientFactory)
            }
        }
    }
}

class ChicagoPizzaStore : PizzaStore() {

    override fun createPizza(type: PizzaType): Pizza {

        val ingredientFactory = ChicagoPizzaIngredientFactory()

        return when (type) {
            PizzaType.CHEESE -> {
                ChicagoStyleCheesePizza(ingredientFactory)
            }
            PizzaType.PEPPERONI -> {
                ChicagoStylePepperoniPizza(ingredientFactory)
            }
        }
    }
}

fun main() {
    val nyStore: PizzaStore = NYPizzaStore()
    nyStore.orderPizza(PizzaType.CHEESE)

    println("------------------------------------------------------")

    val chicagoStore: PizzaStore = ChicagoPizzaStore()
    chicagoStore.orderPizza(PizzaType.PEPPERONI)
}

실행 결과