- 팩토리 패턴은 크게 3가지 정도가 있다.
- Simple Factory (엄밀히 말하면 패턴은 아니다)
Simple Factory
엄밀히 말하면 패턴은 아니다.
프로그래밍에서 자주 쓰이는 관용구 정도의 방식이다.
상황
- 피자 가게에 주문을 받고, 피자를 만드는 시스템이 있다.
- 피자의 종류에 상관없이 피자를 굽고, 자르고, 포장하는 과정은 모두 똑같다.
class PizzaStore(val factory: SimplePizzaFactory) {
fun orderPizza(type: String): Pizza {
val pizza = factory.createPizza(type)
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
return pizza
}
}
class SimplePizzaFactory {
fun createPizza(type: String): Pizza {
if (type == "chicago") {
return ChicagoPizza()
} else {
return CheesePizza()
}
}
}
interface Pizza {
fun prepare()
fun bake()
fun cut()
fun box()
}
class CheesePizza : Pizza {
override fun prepare() {
}
override fun bake() {
}
override fun cut() {
}
override fun box() {
}
}
class ChicagoPizza : Pizza {
override fun prepare() {
}
override fun bake() {
}
override fun cut() {
}
override fun box() {
}
}
- 인스턴스를 생성하는 역할을 팩토리 클래스에 위임했다.
- 피자 종류가 추가되어도
PizzaStore
를 변경하지 않아도 된다.

Factory Method Pattern
팩토리 메소드 패턴은 슈퍼 클래스에 객체를 생성할 때 필요한 인터페이스를 만든다.
어떤 클래스의 인스턴스를 만들지는 서브 클래스에게 맡기는 것이다.

Creator
(슈퍼 클래스)는 사용할 객체를 만드는 메소드를 가지고 있다. Product
를 반환받아 작업을 할 뿐이다. Product
가 무엇인지는 모른다.
- ex) 라인 조립을 한다고 하자. 나사들 가져와서 임팩트 드릴로 박아야한다.
- 라인 작업자가 해야할 일
- 나사를 만들어주세요.
- 나사를 조립한다.
- 라인 작업자는 나사의 재질이 무엇이고 어느 공장에서 만들어진건지 알 필요가 없다.
상황
Simple Factory 패턴에 이어서, 이제 피자 가게를 확장하기로 했다.
피자를 만드는 과정은 똑같지만, 피자에는 지역 색이 들어간다.
K-Pizza, Italian Pizza, Chicago Pizza, Newyork Pizza …
기존의 방식을 써볼까?

바꿔보자
package design_pattern
abstract class PizzaStore {
fun orderPizza(type: String): Pizza {
val pizza = createPizza(type)
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
return pizza
}
abstract fun createPizza(type: String): Pizza
}
class KoreanPizzaStore : PizzaStore() {
override fun createPizza(type: String): Pizza? {
return when(type) {
"cheese" -> KoreanStyleCheesePizza()
"pepperoni" -> KoreanStylePepperoniPizza()
"combination" -> KoreanStyleCombinationPizza()
"potato" -> KoreanStylePotatoPizza()
else -> null
}
}
}
class NYPizzaStore : PizzaStore() {
override fun createPizza(type: String): Pizza? {
return when(type) {
"cheese" -> NYStyleCheesePizza()
"pepperoni" -> NYStylePepperoniPizza()
"combination" -> NYStyleCombinationPizza()
"potato" -> NYStylePotatoPizza()
else -> null
}
}
}
interface Pizza {
fun prepare()
fun bake()
fun cut()
fun box()
}
class NYStylePotatoPizza : Pizza {
}
class NYStyleCombinationPizza : Pizza {
}
class NYStylePepperoniPizza : Pizza {
}
class NYStyleCheesePizza : Pizza {
}
class KoreanStylePotatoPizza : Pizza {
}
class KoreanStyleCombinationPizza : Pizza {
}
class KoreanStylePepperoniPizza : Pizza {
}
class KoreanStyleCheesePizza : Pizza {
}

- 실제로 클라이언트가 스토어 구현체에 주문하는 것은 아니지만, 무슨 피자를 만들 것인지는 구현체(서브클래스)에 정의되어 있기 때문에 이렇게 그려봤다.

Abstract Factory Pattern
추상 팩토리 패턴은 구현 클래스에 의존하지 않고, 서로 연관되거나 의존적인 객체로 이루어진 제품군(Family)을 생산하는 인터페이스를 제공하는 패턴이다.


- 사용자는 추상적인 Product만 알고 사용한다. 실제로 어떤 것인지는 상관없다. (팩토리 메소드 패턴도 동일)
- 팩토리를 통해 반환받은 Product만 사용한다.
- 사용하는 방법은 똑같기 때문에, Mac에서 노션을 쓰든, Windows에서 노션을 쓰든 동일한 GUI를 사용할 수 있다.
상황
피자가게가 전세계로 나아가다 보니, 서로 쓰는 재료가 달라졌다.
그러다보니 같은 나라의 지점이라도 지점 별로 다른 원산지의 재료를 쓰고 있었다.
각 나라별로 원재료를 공급하는 공장을 만들어 피자의 품질을 올리자.
interface PizzaIngredientFactory {
fun createDough(): Dough
fun createSource(): Source
fun createCheese(): Cheese
fun createPepperoni(): Pepperoni
}
class NYPizzaIngredientFactory : PizzaIngredientFactory {
override fun createDough(): Dough {
return ThinCrustDough()
}
override fun createSource(): Source {
return MarinaraSource()
}
override fun createCheese(): Cheese {
return ReggianoCheese()
}
override fun createPepperoni(): Pepperoni {
return SlicedPepperoni()
}
}
interface Pizza {
var dough: Dough
var source: Source
var cheese: Cheese
var pepperoni: Pepperroni
fun prepare()
fun bake()
fun cut()
fun box()
}
class PepperoniPizza(private val factory: PizzaIngredientFactory) : Pizza {
override fun prepare() {
dough = factory.createDough()
source = factory.createSource()
cheese = factory.createCheese()
pepperoni = factory.createPepperoni()
}
override fun bake() {
TODO("Not yet implemented")
}
override fun cut() {
TODO("Not yet implemented")
}
override fun box() {
TODO("Not yet implemented")
}
}
class NYPizzaStore : PizzaStore() {
override fun createPizza(type: String): Pizza? {
val factory: PizzaIngredientFactory = NYPizzaIngredientFactory()
return when(type) {
"cheese" -> CheesePizza(factory)
"pepperoni" -> PepperoniPizza(factory)
"combination" -> CombinationPizza(factory)
"potato" -> PotatoPizza(factory)
else -> null
}
}
}
출처
https://refactoring.guru/ko/design-patterns/factory-method
https://refactoring.guru/ko/design-patterns/abstract-factory
https://ko.wikipedia.org/wiki/추상_팩토리_패턴
Uploaded by N2T