정의
복잡한 객체들을 단계별로 생성할 수 있도록 하는 생성 디자인 패턴입니다.
이 패턴을 사용하면 같은 제작 코드를 사용하여 객체의 다양한 유형들과 표현을 제작할 수 있습니다.
빌더 패턴은 텔레스코핑 생성자 안티 패턴에 대한 해결책을 제공합니다.
public class BuilderEx {
static class House{
String interior; //내장재
String exterior; //외장재
int floor; // 층수
int room; // 방수
int window;// 창문수
public House(String interior, String exterior, int floor, int room, int window) {
super();
this.interior = interior;
this.exterior = exterior;
this.floor = floor;
this.room = room;
this.window = window;
}
@Override
public String toString() {
return "House [interior=" + interior + ", exterior=" + exterior + ", floor=" + floor + ", room=" + room
+ ", window=" + window + "]";
}
}
public static void main(String[] args) {
System.out.println(new House("황토", "나무", 2, 4, 10));
//이 코드 한줄만 보고 뭐가 내장재인지, 외장재인지
//뭐가 층수, 방수, 창문수인지 알 수가 없다.
}
위 처럼 생성자 인수가 늘어날 수록 순서를 신경써야한다.
빌더 적용
//빌더
static interface Builder{
//편의상 메서드 체이닝을 적용한 경우가 많다.
Builder setInterior(String interior);
Builder setExterior(String exterior);
Builder setFloor(int floor);
Builder setRoom(int room);
Builder setWindow(int window);
//생성 메서드는 단일 계층 구조엔 상관없으나, 다중 계층구조이면 서브클래스에 위임한다.
//리턴하는 객체 타입이 다르기 때문이다.
House build();
}
static class HouseBuilder implements Builder{
//기존 코드가 설정자 메서드를 지원한하기에 임시로 값을 저장해둔다.
String interior; //내장재
String exterior; //외장재
int floor; // 층수
int room; // 방수
int window;// 창문수
public Builder setInterior(String interior) {
this.interior = interior;
return this;
}
public Builder setExterior(String exterior) {
this.exterior = exterior;
return this;
}
public Builder setFloor(int floor) {
this.floor = floor;
return this;
}
public Builder setRoom(int room) {
this.room = room;
return this;
}
public Builder setWindow(int window) {
this.window = window;
return this;
}
@Override
public House build() {
//검증 로직이 존재할 수도 있을 것, 혹은 기본값으로 설정되지 않은 값을 대신 할 수도 있다.
if(interior == null && exterior == null
&& floor == 0&& room == 0&& window == 0) {
//기본적으로 빌더 패턴은 사용자가 생성구조를 잘 파악하고 있어야 함을 전제로 한다.
throw new IllegalArgumentException("인수가 부족합니다.");
}
try {
return new House(interior, exterior, floor, room, window);
}finally {
interior = null;
exterior = null;
floor = 0;
room = 0;
window = 0;
}
}
}
public static void main(String[] args) {
Builder houseBuilder = new HouseBuilder();
houseBuilder.setExterior("나무");
houseBuilder.setInterior("대리석");
houseBuilder.setFloor(2);
houseBuilder.setRoom(5);
houseBuilder.setWindow(10);
System.out.println(houseBuilder.build());
houseBuilder.setExterior("콘크리트")
.setInterior("유리")
.setFloor(1)
.setRoom(1)
.setWindow(10);
System.out.println(houseBuilder.build());
}
빌더 패턴에선 기본적으로 사용자가 생성할 객체 구성을 직접 디자인한다. 따라서 잘알고 있다고 가정을 한다.
이렇게 객체 구조를 잘 알아야한다는 것이 단점이다.
디렉터
디렉터 클래스를 두어 자주쓰는 구성 정보를 재사용할 수도 있다.
static class HouseDirector{
public void house1(Builder builder) {
builder.setExterior("나무");
builder.setInterior("대리석");
builder.setFloor(2);
builder.setRoom(5);
builder.setWindow(10);
}
public void house2(Builder builder) {
builder.setExterior("콘크리트")
.setInterior("유리")
.setFloor(1)
.setRoom(1)
.setWindow(10);
}
}
public static void main(String[] args) {
Builder houseBuilder = new HouseBuilder();
HouseDirector houseDirector = new HouseDirector();
houseDirector.house1(houseBuilder);
System.out.println(houseBuilder.build());
houseDirector.house2(houseBuilder);
System.out.println(houseBuilder.build());
}
자주 보는 클래스에 빌더 패턴 사례
'개발 > 디자인 패턴' 카테고리의 다른 글
생성 - 프로토타입(Prototype) (0) | 2023.05.13 |
---|---|
구조 - 플라이웨이트(Flyweight) (0) | 2023.05.09 |
행동 - 책임 연쇄 패턴(Chain of Responsibility) (0) | 2023.05.06 |