[디자인 패턴] 팩토리 메소드

Benji Android·2022년 5월 10일
0

디자인 패턴

목록 보기
1/7
post-thumbnail

정의

객체지향 다형성의 원리를 기반으로 만들어짐
다양한 구현체(Product)가 있고, 특정한 구현체를 만들 수 있는 팩토리(Creator)를 제공

확장에는 열려있고 변경에는 닫혀 있는 구조

부모(상위) 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며, 자식(하위) 클래스가 어떤 객체를 생성할지 결정하도록 하는 패턴이다.

  • Product
    공통으로 생성될 객체의 인터페이스

  • ConcreateProduct
    구체적으로 객체가 생성되는 클래스

  • Creator
    팩토리 매서드를 가지고 있는 클래스

  • ConcreateCreator
    팩토리 매서드를 구현하는 클래스, ConcreateProduct 객체 생성


구현할 팩토리 매소드 클래스


생성자(Product) 만들기

  • 생성자 Pizza 클래스를 만들어 봅니다.
abstract class Pizza {

    var name: String = ""
    var dough: String = ""
    var sauce: String = ""

    override fun toString(): String {
        return """
            { name : $name, dough : $dough, sauce : $sauce }
        """.trimIndent()
    }

    fun prepare() {
        println("Prepare $name")
        println("도우 셋팅 중...")
        println("소스 추가 중...")
        println("토핑 추가 중: ")
    }

    fun bake() {
        println("25분 동안 피자를 굽습니다.")
    }

    fun cut() {
        println("피자를 8등분으로 자릅니다.")
    }

    fun box() {
        println("피자 박스에 피자를 담고 있습니다.")
    }
}

피자에는 총 3가지의 변수를 가집니다.

  • name: 피자의 이름
  • dough: 도우 종류
  • sauce: 소스의 종류

피자를 준비에 필요한 행동(매소드)를 정의합니다.

  • fun prepare(): 피자를 만들기 위한 준비
  • fun bake(): 피자 굽기
  • fun cut(): 피자 자르기
  • fun box(): 피자를 박스에 담기

여기서 피자는 어떤 피자를 만들게 될지 모르고 주문이 들어왔을 때,

주문에 맞는 피자를 만들게 됩니다.


ConcreateProduct 클래스 만들기

  • 뉴욕 스타일 피자와 시카고 스타일 피자를 만들어 보겠습니다.
class NYStyleCheesePizza : Pizza() {
    init {
        name = "NY 치즈 피자"
        dough = "치즈 도우"
        sauce = "치즈 소스"
    }
}
class ChicagoStyleCheesePizza: Pizza() {
    init {
        name = "시카고 치즈 피자"
        dough = "두꺼운 도우"
        sauce = "체다 치즈 소스"
    }
}

피자의 종류를 알 수 있는 클래스를 만들었습니다.

PizzaType.kt 에 맞는 Pizza ConcreateProduct 클래스를 만들어 주면 됩니다.

클래스가 많아져도 괜찮습니다.

이제 피자의 종류를 알고 있으니 피자가게에가서 주문하면 됩니다.

주문은 ConcreateCreator 를 통해서 Pizza를 전달하고 Creator에서 만들어 줍니다.


PizzaStore(Creator) 만들기

  • 피자를 만들 수 있는 피자상점을 만들어 봅니다.
abstract class PizzaStore {

    abstract fun createPizza(item: PizzaType): Pizza

    fun orderPizza(type: PizzaType): Pizza {
        val pizza: Pizza = createPizza(type)
        println("--- Making a ${pizza.name} ---")
        return pizza.apply {
            prepare()
            bake()
            cut()
            box()
        }
    }
}

피자의 종류에 따른 Pizza 를 만들어 주문을 넣을 수 있도록 합니다.

enum class PizzaType {
    CHEESE,
    TOMATO,
    CLAM,
    VEGGIE
}

Pizza 객체에 따른 피자를 만들기 위해 abstract fun createPizza(item: PizzaType): Pizza 구현 할 수 있는 ConcreateCreator 클래스를 만들어 주어야 합니다.


ConcreateCreator(뉴욕, 시카고 피자 상점) 만들기

  • 저희는 뉴욕 피자, 시카고 피자 총 2가지의 종류의 피자를 주문할 수 있습니다.
  • 스타일에 맞는 피자 상점을 만들어 PizzaType 으로 어떤 종류의 피자인지 알게됩니다.
class NYPizzaStore: PizzaStore() {
    override fun createPizza(item: PizzaType): Pizza {
        return when(item) {
            PizzaType.CHEESE -> NYStyleCheesePizza()
            PizzaType.TOMATO -> NYStyleTomatoPizza()
            PizzaType.CLAM -> NYStyleClamPizza()
            PizzaType.VEGGIE -> NYStyleVeggiePizza()
            else -> throw IllegalArgumentException()
        }
    }
}
class ChicagoPizzaStore : PizzaStore() {
    override fun createPizza(item: PizzaType): Pizza {
        return when(item) {
            PizzaType.CHEESE -> ChicagoStyleCheesePizza()
            PizzaType.CLAM -> ChicagoStyleClamPizza()
            PizzaType.TOMATO -> ChicagoStyleTomatoPizza()
            PizzaType.VEGGIE -> ChicagoStyleVeggiePizza()
            else -> throw IllegalArgumentException()
        }
    }
}

뉴욕스타일 피자 상점과 시카고 스타일 피자 상점을 만들어 주었습니다.

override fun createPizza(item: PizzaType): Pizza 구현하여 Pizza 객체를 PizzaStore(Creator) 클래스로 주게 됩니다.


결과

fun main() {
    val nyStore = NYPizzaStore()
    val chicagoStore = ChicagoPizzaStore()

    val pizza: Pizza = nyStore.orderPizza(PizzaType.CHEESE)
    println("철수 주문 : ${pizza.name}, \n$pizza")

    print("\n\n")

    val chicagoTomatoPizza: Pizza = chicagoStore.orderPizza(PizzaType.TOMATO)
    println("영희 주문 : ${chicagoTomatoPizza.name}, \n$chicagoTomatoPizza")
}

PizzaType에 맞는 피자를 PizzaStore(Creator) 클래스에서 만들어 주는 모습을 볼 수 있습니다.

간단하게 팩토리 메서드를 활용한 피자만들기를 구현해 보았습니다.


  • Product Diagram

  • Creator Diagarm

장점

기존 코드를 수정하지 않고 새로운 인스턴스를 확장 할 수 있다.
Product - Creator 느슨한 결합으로 만들 수 있다.
코드가 간결해 진다.

단점

클래스가 많아 진다.
제품이 변경, 추가 될 때 마다 클래스를 생성해야한다.

사용 이유

  • 생성할 객체 타입을 예측할 수 없을 때
  • 생성할 객체를 기술하는 책임을 서브클래스에게 정의하고자 할 때
  • 객체 생성의 책임을 서브클래스에 위임시키고 서브클래스에 대한 정보를 은닉하고자 할 때

참고

profile
Android 주니어 개발자

0개의 댓글