객체지향 다형성의 원리를 기반으로 만들어짐
다양한 구현체(Product)가 있고, 특정한 구현체를 만들 수 있는 팩토리(Creator)를 제공확장에는 열려있고 변경에는 닫혀 있는 구조
부모(상위) 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며, 자식(하위) 클래스가 어떤 객체를 생성할지 결정하도록 하는 패턴이다.
Product
공통으로 생성될 객체의 인터페이스
ConcreateProduct
구체적으로 객체가 생성되는 클래스
Creator
팩토리 매서드를 가지고 있는 클래스
ConcreateCreator
팩토리 매서드를 구현하는 클래스, ConcreateProduct 객체 생성
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가지의 변수를 가집니다.
피자를 준비에 필요한 행동(매소드)를 정의합니다.
fun prepare()
: 피자를 만들기 위한 준비fun bake()
: 피자 굽기fun cut()
: 피자 자르기fun box()
: 피자를 박스에 담기여기서 피자는 어떤 피자를 만들게 될지 모르고 주문이 들어왔을 때,
주문에 맞는 피자를 만들게 됩니다.
class NYStyleCheesePizza : Pizza() {
init {
name = "NY 치즈 피자"
dough = "치즈 도우"
sauce = "치즈 소스"
}
}
class ChicagoStyleCheesePizza: Pizza() {
init {
name = "시카고 치즈 피자"
dough = "두꺼운 도우"
sauce = "체다 치즈 소스"
}
}
피자의 종류를 알 수 있는 클래스를 만들었습니다.
PizzaType.kt
에 맞는 Pizza ConcreateProduct 클래스를 만들어 주면 됩니다.
클래스가 많아져도 괜찮습니다.
이제 피자의 종류를 알고 있으니 피자가게에가서 주문하면 됩니다.
주문은 ConcreateCreator 를 통해서 Pizza를 전달하고 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 클래스를 만들어 주어야 합니다.
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 - Creator 느슨한 결합으로 만들 수 있다.
코드가 간결해 진다.
클래스가 많아 진다.
제품이 변경, 추가 될 때 마다 클래스를 생성해야한다.