[Design Go] 팩토리 메소드 패턴

2020. 12. 24. 22:00·소프트웨어 공학

들어가기에 앞서...

이번 패턴의 설명 역시 지난 패턴의 예제를 이용했다.

팩토리 메소드 패턴

팩토리 메소드 패턴은 함수에게 다른 객체(product)의 생성을 맡기는 디자인 패턴이다.  creator 함수는 product 객체의 일종의 생성자 역할을 한다고 볼 수 있다.

장점

  • 객체의 생성과 구현을 분리해낸다. 이전의 생성 패턴들과 같다.
  • 코드의 가독성이 높아진다. 빌더 패턴과 비슷한 이유이다. 빌더 패턴이 거대한 객체의 생성을 목적으로 한다면 팩토리 메소드는 작은 객체의 생성을 목적으로 한다.
  • 다른 패턴과 쉽게 연동된다. 기존의 클래스에 해당 메소드만 추가하면 되는 만큼 다른 패턴에 적용하기 쉽다. 추상 팩토리 패턴은 여러 팩토리 메소드를 묶어 객체화한 패턴이다.

단점

  • 코드가 난잡해질 수 있다. 팩토리 메소드 패턴은 적용하기가 매우 쉽기 때문에 남용할 수 있다. 즉, 이미 적당한 생성자가 있음에도 불구하고 팩토리 메소드 패턴을 사용하면 한 객체에 두가지 생성자가 만들어질 우려가 있다.

구현

사실 우리는 이미 팩토리 메소드 패턴을 구현했다. 다음은 기존 예제의 함수이다.

func NewRoom(idx int) *room {
	r := new(room)
	r.idx = idx
	for i := range r.sides {
		r.sides[i] = NewWall()
	}
	return r
}
// ...
func NewRoomWithBomb(idx int) *roomWithBomb {
	r := new(roomWithBomb)
	r.Room = NewRoom(idx)
	return r
}

새로운 room을 반환하는 함수이다. 이 때 room에 대한 기본적인 처리는 함수 내에서 완료되어 반환된다. 해당 함수를 다듬으면 다음과 같은 모습이 된다.

func NewRoom(idx int) Room {
	r := new(room)
	r.idx = idx
	for i := range r.sides {
		r.sides[i] = NewWall()
	}
	return r
}
//...
func NewRoomWithBomb(idx int) Room {
	r := new(roomWithBomb)
	r.Room = NewRoom(idx)
	return r
}

위의 함수가 바로 팩토리 메소드이다. 위와 달라진 점은 인터페이스로 선언되었다는 것이다. 이는 해당 객체의 내부 변수 및 내부 메소드로의 접근을 제한하고 인터페이스에 정의된 함수만 이용할 수 있게한다. 즉, 해당 객체는 은닉성을 얻게 된다.

팩토리 메소드는 매개변수를 이용해서 생성할 객체를 결정할 수도 있다.

package main

type mazeType int

const (
	simple mazeType = iota
	bomb
)

func NewRoomOf(t mazeType, idx int) Room {
	switch t {
	case simple:
		return NewRoom(idx)
	case bomb:
		return NewRoomWithBomb(idx)
	default:
		warn()
		return nil
	}
}

func NewDoorOf(t mazeType, r1, r2 Room) Door {
	switch t {
	case simple:
		return NewDoor(r1, r2)
	case bomb:
		return NewBombedDoor(r1, r2)
	default:
		warn()
		return nil
	}
}

func warn() {
	panic("Invalid argument")
}

해당 함수는 매개변수를 받아 그에 맞춰 생성할 객체를 결정한다. 오류의 가능성을 줄이기 위해 mazeType 자료형을 선언하고 해당 자료형의 상수를 열거형으로 정의했다.

통상적인 팩토리 메소드는 이미 많이 사용했으므로 매개변수를 이용한 팩토리 메소드의 호출만 보고 마무리짓겠다.

//...

func CreateMaze2(t mazeType) Maze {
	m := NewMaze()

	r1 := NewRoomOf(t, 1)
	r2 := NewRoomOf(t, 2)
	d := NewDoorOf(t, r1, r2)

	m.AddRoom(r1)
	m.AddRoom(r2)

	r1.SetSide(East, d)
	r2.SetSide(West, d)

	return m
}

func main() {
	simpleM := CreateMaze()
	play(simpleM)

	m := CreateMaze2(simple)
	play(m)

	m = CreateMaze2(bomb)
	play(m)
}

 

Entered to room 1
door is Open. Successfully entered.
Entered to room 1
Bomb!
Door was bombed. Successfully entered.

마치며...

팩토리 메소드 패턴과 추상 팩토리 패턴은 묶어서 팩토리 패턴이라고 불리기도 한다. 그만큼 팩토리 패턴과 팩토리 메소드 패턴은 같이 쓰이는 경우가 많다.

팩토리 메소드 패턴은 범용적으로 쓰이지만 특별한 형식을 요하지 않는 만큼 패턴이라 하기 애매하기도 하다. 그래서 해당 패턴은 혼자 쓰이기 보다는 다른 패턴에 곁들어서 쓰인다. 다른 패턴들이 하나의 완성된 음식이라면 팩토리 메소드는 조미료인 것이다.

참고 자료

  • GoF(에릭 감마, 리처드 헬름, 랄프 존슨, 존 블리시디스), GoF의 디자인 패턴, 프로텍 미디어, 2015
  • Dmitri Nesteruk, Design Patterns in Go, Udemy, 2020.8
저작자표시 (새창열림)
'소프트웨어 공학' 카테고리의 다른 글
  • [Design Go] 단일체 패턴(동시성 프로그래밍을 중심으로)
  • [Design Go] 원형 패턴
  • [Design Go] 추상 팩토리 패턴
  • [Design Go] 빌더 패턴
박정현
박정현
Go언어에 대한 전반적인 것을 다룹니다.
  • 박정현
    Simple & Clear
    박정현
  • 전체
    오늘
    어제
    • 분류 전체보기 (39)
      • 프로그래밍 언어 (13)
      • 툴, 프레임워크, 기술 (6)
      • 소프트웨어 공학 (13)
      • 회고 (5)
      • 서평 (2)
  • 블로그 메뉴

    • 홈
    • 태그
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    코딩챌린지
    TDD
    모드버스
    동시성 프로그래밍
    커맨드라인
    가교 패턴
    go언어
    go test
    디자인 패턴
    회고
    Solid
    chan chan
    Deep Copy
    codingchallenge
    design pattern
    sqlc
    프로토콜
    테스트 주도 개발
    워커 풀 패턴
    문법
    생성 패턴
    서평
    db
    modbus
    객체지향 프로그래밍
    OOP
    깊은 복사
    go-migrate
    DIP
    golang
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
박정현
[Design Go] 팩토리 메소드 패턴
상단으로

티스토리툴바