GoF 생성 패턴 중 하나인 Builder에 대해 알아보겠습니다.
인스턴스를 생성하다 보면 다양한 구성이 필요한 경우가 있습니다. 모든 프로퍼티 값이 필요한 인스턴스도 있고 그렇지 않은 인스턴스도 존재합니다.
Builder 패턴은 인스턴스를 만드는 과정을 동일한 프로세스를 통해 해결하는 패턴입니다.
Client 쪽에서 직접 Builder를 사용할 수도 있지만 Director를 통해 builder를 사용하면 반복되는 builder 호출을 숨길 수 있습니다.
패턴 적용 전
class TourPlan {
var title: String?
var days: Int?
var lodging: String?
var plan: [Int: [String]] = [:]
init(title: String?, days: Int?, lodging: String?) {
self.title = title
self.days = days
self.lodging = lodging
}
convenience init() {
self.init(title: nil, days: nil, lodging: nil)
}
convenience init(title: String, days: Int) {
self.init(title: title, days: days, lodging: nil)
}
func setTitle(title: String) {
self.title = title
}
func setDays(days: Int) {
self.days = days
}
func bookLodging(lodging: String) {
self.lodging = lodging
}
func addPlan(day: Int, detailPlan: String) {
if self.plan[day] == nil {
self.plan[day] = []
}
self.plan[day]?.append(detailPlan)
}
}
TourPlan 이라는 타입이 있습니다. 해당 타입을 통해 인스턴스를 생성하는 과정은 아래와 같습니다.
let longTour = TourPlan()
longTour.setTitle(title: "일본 여행")
longTour.setDays(days: 2)
longTour.bookLodging(lodging: "호텔")
longTour.addPlan(day: 1, detailPlan: "체크인")
longTour.addPlan(day: 1, detailPlan: "오사카 투어")
longTour.addPlan(day: 2, detailPlan: "체크아웃")
longTour.addPlan(day: 2, detailPlan: "교토 이동")
let shortTour = TourPlan()
shortTour.setTitle(title: "당일치기 기차 여행")
shortTour.setDays(days: 1)
shortTour.addPlan(day: 1, detailPlan: "9시 출발")
긴 여행이냐 짧은 여행이냐에 따라 필요한 구성이 달라지는 걸 확인할 수 있습니다.
init()
와convenience init()
을 통해 경우에 따른 생성자를 구현할 수도 있습니다. 관리해야 하는 생성자의 수가 많아지고 사용할 때 헷갈릴 수 있습니다.
패턴 적용
protocol TourBuilder {
func setTitle(title: String) -> TourBuilder
func setDays(days: Int) -> TourBuilder
func bookLodging(lodging: String) -> TourBuilder
func getTourPlan() -> TourPlan
}
class DefaultTourBuilder: TourBuilder {
var title: String?
var days: Int?
var lodging: String?
func setTitle(title: String) -> TourBuilder {
self.title = title
return self
}
func setDays(days: Int) -> TourBuilder {
self.days = days
return self
}
func bookLodging(lodging: String) -> TourBuilder {
self.lodging = lodging
return self
}
func getTourPlan() -> TourPlan {
return TourPlan(title: self.title, days: self.days, lodging: self.lodging)
}
}
let longTourBuilder = DefaultTourBuilder()
let japanTour = longTourBuilder.setTitle(title: "일본 여행")
.setDays(days: 2)
.bookLodging(lodging: "리조트")
.getTourPlan()
각 메서드를 통해 필요한 값을 설정하고 getTourPlan()
메서드를 통해 인스턴스를 생성할 수 있습니다.
class Director {
let builder: TourBuilder
init(builder: TourBuilder) {
self.builder = builder
}
func getJapanTourPlan() -> TourPlan {
return builder.setTitle(title: "일본 여행")
.setDays(days: 2)
.bookLodging(lodging: "리조트")
.getTourPlan()
}
}
let tourPlanDirector = Director(builder: DefaultTourBuilder())
let japanTourPlan = tourPlanDirector.getJapanTourPlan()
Director를 사용한다면 위에 코드처럼 작성할 수 있습니다. 또 한 위에 얘기한 대로 Director에 메서드를 정의해 자주 사용되는 인스턴스 구성을 미리 만들 수 있습니다.
해당 글은 인프런의 코딩으로 학습하는 GoF 디자인 패턴 강의와 블로그를 참고해 작성했습니다.
참고 블로그
Refactoring.Guru
⭐️ 부족하거나 잘못된 부분이 있다면 댓글은 언제나 환영입니다!! ⭐️