디자인 패턴을 구현해보지 않으면 객체 지향 프로그램을 다뤘다고 하기 어렵다
팩토리 패턴은 어떤 객체를 만들지 전적으로 팩토리에 위임한다
type Show = {
purpose: string
}
class BalletFlat implements Shoe {
purpose = 'dancing'
}
class Sneaker implements Show {
purpose = 'walking'
}
위 예제에서 타입을 사용하였지만 인터페이스를 사용해도 된다
다음은 팩토리
let Shoe = {
// 타입을 유니온으로 지정하여 .create 의 타입 안정성 강화
create (type: 'dancing' | 'sneaker'): Shoe {
// 스위치 문을 사용해 누락된 Shoe 타입에 대해 타입스크립트가 쉽게 확인할 수 있도록 한다
switch (type) {
case 'balletFlat': return new BalletFlat
break
case 'sneaker': return new Sneaker
break
}
}
}
위 예에선 캠패니언 객체 패턴으로 타입 Shoe 와 값 Shoe 를 같은 이름으로 선언했다
팩토리를 사용하려면 .create() 를 호출한다
Shoe.create('sneaker') // Shoe
팩토리 패턴의 추상화는 Shoe 를 반환하여 어떤 구체 클래스가
일을 하는지 알 수 없도록 한다
호출자는 팩토리가 특정 인터페이스를 만족하는 클래스를 제공할 것이라는
사실만 알 뿐 어떤 구체 클래스가 이 일을 하는지
알 수 없어야 한다
빌터 패턴으로 객체의 생성과 구현을 분리할 수 있다
Map, Set 자료구조를 사용해봤다면 빌더 배턴이 친숙할 것이다
new RequestBuilder()
.setURL('/users')
.setMethod('get')
.setData({ firstName: 'Anna' })
.send()
RequestBuilder 는 다음과 같이 구현한다
class RequestBuilder {} // 뼈대 구현
class RequestBuilder {
private url: string | null = null // 초기값 null 인 비공개 변수
// 반환 타입은 this 로 호출한 특정 RequestBuilder 의 인스턴스
setURL(url: string): this {
this.url = url
return this
}
}
class RequestBuilder {
private data: object | null = null
private url: string | null = null
private method: 'get' | 'post | null = null
setURL(url: string): this {
this.url = url
return this
}
setMethod(method: 'get' | 'post'): this {
this.method = method
return this
}
setData(data: object): this {
this.data = data
return this
}
send() {
//...
}
}
위와 같은 빌더 패턴은 안전하지 않다
다른 메서드를 정의하지 않은 상태에서 .send 를 호출할 수 있으므로
런타임 예외가 발생할 수 있다
타입 안전성을 갖춘 빌터 패턴에 대해 생각해봐야 한다..