빌더 패턴이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴
복잡한 객체를 단계별로 초기화해야 하는 경우 많은 매개변수를 필요로 합니다. 이러한 매개변수는 거대한 생성자를 만들게 되고 모든 매개변수가 항상 필요하지는 않기 때문에 호출 부분의 코드가 매우 못생겨질 것입니다.
AlertController
를 사용해서 alert를 띄워주려는데 성공케이스와 실패케이스에 하드코딩하는 것이 보기 좋지 않았습니다. alert는 title, message, preferredStyle, action을 추가해줘야하기 때문에 이를 단계적으로 생성을 하고 서로 다른 객체를 구조화해서 사용하기위해 빌더 패턴을 적용해봤습니다. 빌더 단계들에 대한 일련의 호출을 디렉터라는 별도의 클래스로 추출할 수 있습니다. 디렉터 클래스는 순서를, 빌더는 구현을 정의합니다.
Java에서의 Implement는 Swift에서 protocol의 개념으로 사용합니다.
protocol Builder {
func setServer(_ server: Server) -> Builder
func setJob(_ job: Job) -> Builder
func setGender(_ gender: Gender) -> Builder
}
class CharactorBuilder: Builder {
private var user = User()
func reset() {
user = User()
}
func setServer(_ server: Server) -> Builder {
user.server = server
return self
}
func setJob(_ job: Job) -> Builder {
user.job = job
return self
}
func setGender(_ gender: Gender) -> Builder {
user.gender = gender
return self
}
func buildUser() -> User {
let user = self.user
reset()
return user
}
}
return self
를 통해 호출부에서 체이닝 형태로 객체를 구현할 수 있습니다.reset
함수는 실제 유저객체를 내보낼 때 실행함으로써 다음 빌더는 비어있는 상태로 만듭니다. class Director {
private var builder: Builder?
func update(builder: Builder) {
self.builder = builder
}
func makeDefaultUser() {
_ = builder?
.setGender(.남)
.setServer(.아시아)
.setJob(.전사)
}
func makeSpecialUser() {
_ = builder?
.setServer(.유럽)
.setJob(.궁수)
}
}
class User {
var server: Server?
var job: Job?
var gender: Gender?
}
enum Server {
case 아시아
case 유럽
case 남미
}
enum Job {
case 전사
case 마법사
case 궁수
}
enum Gender {
case 남
case 여
}
let director = Director()
let builder = CharactorBuilder()
director.update(builder: builder)
director.makeDefaultUser()
print(builder.buildUser().gender)
director.makeSpecialUser()
print(builder.buildUser().gender)
// Optional(BuilderDesignPattern.Gender.남)
// nil