# 팩토리패턴
## 팩토리 패턴의 종류
팩토리패턴의 종류는 크게 아래 2가지가 있다.
1. 팩토리 메서드 패턴
2. 추상 팩토리 패턴
번외 심플 팩토리
이제 하나씩 알아보자!
## 팩토리 메서드 패턴
- 팩토리 메서드는 심플팩토리에서 팩토리 자체를 추상화를 시키고 각각의 구체적인 팩토리 클래스가 특정 타입의 객체 생성을 담당하는 패턴
- 새로운 타입의 객체를 추가하려면 새로운 팩토리 클래스만 추가 하면 되기 때문에 OCP를 준수한다.
<팩토리 메서드 패턴>
1. 추상클래스로 팩토리와 로봇을 만들어준다.
abstract class 로봇 {
abstract fun 설명(): String
}
abstract class 로봇팩토리(){
abstract fun 로봇제작() : 로봇
}
2. 구체적인 로봇 클래스를 정의 해준다.
class 뛰는로봇():로봇(){
override fun 설명(): String{
return "뛰는 로봇 입니다"
}
}
class 걷는로봇():로봇(){
override fun 설명(): String{
return "걷는 로봇 입니다"
}
}
3. 팩토리를 상속 받는 구체적인 로봇 팩토리를 정의해준다.
class 뛰는로봇팩토리():로봇팩토리(){
override fun 로봇제작(): 로봇{
return 뛰는로봇()
}
}
class 걷는로봇팩토리():로봇팩토리(){
override fun 로봇제작(): 로봇{
return 걷는로봇()
}
}
4. 메인 클래스에서 팩토리 메서드를 이용하여 정의
fun main() {
val 걷는로봇팩토리객체: 로봇팩토리 = 걷는로봇팩토리()
val 걷는로봇객체: 로봇 = 걷는로봇팩토리객체.로봇제작()
println(걷는로봇객체.설명())
val 뛰는로봇팩토리객체: 로봇팩토리 = 뛰는로봇팩토리()
val 뛰는로봇객체: 로봇 = 뛰는로봇팩토리객체.로봇제작()
println(뛰는로봇객체.설명())
}
## 추상 팩토리 패턴
- 연관된 객체들을 모아둔다는것에 집중하는 패턴
코드에서 예를 들면 로봇의 부품까지 하나의 팩토리에서 담당한다고 보면 됨
<추상 팩토리 패턴>
1. 메인인 로봇과 관련된 부품을 interface로 정의
interface 로봇 {
fun 설명(): String
}
interface 부품 {
fun 부품설명(): String
}
2. 로봇팩토리 생성
interface 로봇팩토리 {
fun 로봇제작() : 로봇
fun 부품제작() : 부품
}
3. 구체적인 로봇 클래스와 부품 클래스 정의
class 뛰는로봇: 로봇 {
override fun 설명(): String {
return "뛰는 로봇 입니다"
}
}
class 걷는로봇: 로봇 {
override fun 설명(): String {
return "걷는 로봇 입니다"
}
}
class 뛰는로봇부품: 부품 {
override fun 부품설명(): String {
return "뛰는 로봇의 부품입니다"
}
}
class 걷는로봇부품: 부품 {
override fun 부품설명(): String {
return "걷는 로봇의 부품입니다"
}
}
4. 팩토리를 상속 받는 구체적인 로봇 팩토리를 정의
class 뛰는로봇팩토리: 로봇팩토리 {
override fun 로봇제작(): 로봇 {
return 뛰는로봇()
}
override fun 부품제작(): 부품 {
return 뛰는로봇부품()
}
}
class 걷는로봇팩토리: 로봇팩토리 {
override fun 로봇제작(): 로봇 {
return 걷는로봇()
}
override fun 부품제작(): 부품 {
return 걷는로봇부품()
}
}
5. 메인 클래스에서 로봇 객체와 부품 객체를 정의
val 걷는로봇팩토리객체: 로봇팩토리 = 걷는로봇팩토리()
val 걷는로봇객체: 로봇 = 걷는로봇팩토리객체.로봇제작()
println(걷는로봇객체.설명())
val 걷는로봇부품객체: 부품 = 걷는로봇팩토리객체.부품제작()
println(걷는로봇부품객체.부품설명())
val 뛰는로봇팩토리객체: 로봇팩토리 = 뛰는로봇팩토리()
val 뛰는로봇객체: 로봇 = 뛰는로봇팩토리객체.로봇제작()
println(뛰는로봇객체.설명())
val 뛰는로봇부품객체: 부품 = 뛰는로봇팩토리객체.부품제작()
println(뛰는로봇부품객체.부품설명())
## 번외 심플 팩토리
- 심플 팩토리는 객체 생성하는 작업을 다른 클래스에 위임한다는것으로 볼 수 있다.
- 심플팩토리는 디자인패턴이라고 할 수 없고 코딩에서 자주 쓰이는 관용구라고 보면 된다.
심플 팩토리 예제
[시나리오]
로봇들이있고 각 로봇 별로 움직이는 방식이 다르다는 시나리오 이다.
<기본 코드>
interface 로봇 {
fun 설명()
}
class 걷는로봇():로봇{
override fun 설명(){
println("걷는 로봇 입니다")
}
}
class 뛰는로봇():로봇{
override fun 설명(){
println("뛰는 로봇 입니다")
}
}
fun main() {
val 걷는로봇객체:걷는로봇 = 걷는로봇()
val 뛰는로봇객체:뛰는로봇 = 뛰는로봇()
걷는로봇객체.설명()
뛰는로봇객체.설명()
}
이렇게 되면 우선 메인클래스와 각 로봇클래스들 사이에 의존관계가 생긴다.
만약 구현클래스(로봇클래스)가 변경되었을때는 의존하고 있는 모든 클래스의 코드를 변경 해야하는 단점이 있다.
이래서 주로 사용하는것은 심플 팩토리 이다.
<심플 팩토리>
interface 로봇 {
fun 설명()
}
class 걷는로봇():로봇{
override fun 설명(){
println("걷는 로봇 입니다")
}
}
class 뛰는로봇():로봇{
override fun 설명(){
println("뛰는 로봇 입니다")
}
}
// 팩토리 클래스 생성
class 로봇팩토리(){
// 객체 생성을 하는 메서드 생성
fun 로봇제작(로봇타입: String) : 로봇 {
return when(로봇타입){
"걷는로봇" -> 걷는로봇()
"뛰는로봇" -> 뛰는로봇()
else -> 걷는로봇()
}
}
}
fun main() {
val 로봇팩토리객체 = 로봇팩토리()
var 로봇객체:로봇 = 로봇팩토리객체.로봇제작("걷는로봇")
로봇객체.설명()
로봇객체 = 로봇팩토리객체.로봇제작("뛰는로봇")
로봇객체.설명()
}
이런 식으로 심플 팩토리로 하면 메인 클래스에서는 구현 클래스에 직접 의존하지 않기 때문에 구현 클래스가 변경이 되더라도 팩토리 클래스 내부만 수정하기 때문에 편리하다.
하지만 심플 팩토리는 OCP 원칙에 위배돼서 디자인 패턴은 아니다!