Builder Parttern이란?
Builder Pattern은 디자인 패턴의 종류(생성, 구조, 행동) 중 생성 디자인 패턴에 속한다.
객체를 만드는 방법이 여러 가지 일때, 즉 옵션이 많은 객체를 만들어야할 때 사용함
Builder Pattern을 쓰는 이유 (== 기존 개발 형태에 대한 문제점)?
만일 집(아파트가 아닌 독립 주택)이라는 클래스가 있다고 하자.
해당 집에는 지붕, 방, 창문, 화장실, 마당, 발코니 등 여러 요소가 있고 할때 이를 클래스로 구현하면 다음과 같다.
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
}
이 클래스의 객체를 생성하기 위해서는 기존에는 두가지 방법으로 구현했다.
1. 점층적 생성자 패턴
2. 자바 빈즈 패턴
1. 점층적 생성자 패턴
이름 그대로 여러 개의 필드가 있을 때 점층적으로 생성자를 만들어두는 방법이다.
점층적 생성자 패턴은 다음과 같다.
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
public House(int rooms, int toilets, int windows) {
this.rooms = rooms;
this.rooms = toilets;
this.windows = windows;
}
public House(int rooms, int toilets, int windows, int floors) {
this.rooms = rooms;
this.rooms = toilets;
this.windows = windows;
this.floors = floors;
}
public House(int rooms, int toilets, int windows, int floors, boolean hasBalcony) {
this.rooms = rooms;
this.rooms = toilets;
this.windows = windows;
this.floors = floors;
this.hasBalcony = hasBalcony;
}
public House(int rooms, int toilets, int windows, int floors, boolean hasBalcony, boolean hasBackyard) {
this.rooms = rooms;
this.rooms = toilets;
this.windows = windows;
this.floors = floors;
this.hasBalcony = hasBalcony;
this.hasBackyard = hasBackyard;
}
}
이런 점층적 생성자 패턴을 이용해 House 클래스를 인스턴스화 해보자.
public static void main(String[] args) {
House myhouse = new House(3, 2, 3, 2, false, false);
}
필드(프로퍼티)가 많을 때 가독성이 떨어진다. 앞에 나와있는 3이 무슨 필드였고 뒤에 나오는 false들이 무슨 필드를 뜻하는지 외우지 않는 이상 알기가 어렵다.
또한 House 클래스에 필드를 추가할때 별도로 생성자를 만들거나 수정해줘야 null 값이 없는 완전한 객체를 만들 수 있다.
2. 자바 빈즈 패턴
이 패턴은 앞서 점층적 생성자 패턴과 달리 매개변수가 없는 생성자로만 객체를 만든 후, setter 메서드를 호출해 원하는 매개변수의 값을 설정하는 방법이다.
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
public House() {}
public void setRooms(int rooms) {
this.rooms = rooms;
}
public void setToilets(int toilets) {
this.toilets = toilets;
}
public void setWindows(int windows) {
this.windows = windows;
}
public void setFloors(int floors) {
this.floors = floors;
}
public void setHasBalcony(boolean hasBalcony) {
this.hasBalcony = hasBalcony;
}
public void setHasBackyard(boolean hasBackyard) {
this.hasBackyard = hasBackyard;
}
public static void main(String[] args) {
House myhouse = new House();
myhouse.setRooms(3);
myhouse.setToilets(2);
myhouse.setWindows(3);
myhouse.setFloors(2);
myhouse.setHasBalcony(false);
myhouse.setHasBackyard(false);
}
}
자바 빈즈 패턴을 사용하면 이전 점층적 생성자 패턴보다는 어떤 필드 값에 어떤 값을 가지는지 조금 명확해졌지만 setter 메서드로 인해 불변성이 깨진다는 것이 단점이다.
Builder Pattern(빌더 패턴) 구현 방법
빌더 패턴은 Builder 클래스를 별도로 만들어주면 된다.
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
public static class HouseBuilder {
private House house;
public HouseBuilder() {
this.house = new House();
}
public HouseBuilder rooms(int rooms) {
this.house.rooms = rooms;
return this;
}
public HouseBuilder toilets(int toilets) {
this.house.toilets = toilets;
return this;
}
public HouseBuilder windows(int windows) {
this.house.windows = windows;
return this;
}
public HouseBuilder floors(int floors) {
this.house.floors = floors;
return this;
}
public HouseBuilder hasBalcony(boolean hasBalcony) {
this.house.hasBalcony = hasBalcony;
return this;
}
public HouseBuilder hasBackyard(boolean hasBackyard) {
this.house.hasBackyard = hasBackyard;
return this;
}
public House build() {
return this.house;
}
}
public static void main(String[] args) {
House myhouse = new HouseBuilder()
.rooms(3)
.toilets(2)
.windows(3)
.floors(2)
.hasBalcony(false)
.hasBackyard(false)
.build();
}
}
우리는 이 빌더 패턴으로 점층적 생성자 패턴과 같이 불변성을 보장할 수 있고, 자바 빈즈 패턴처럼 어떤 필드에 어떤 값을 가지는지 가독성을 높일 수 있다. 그리고 추가적으로 체이닝기법을 사용해서 연속적으로 쓸 수 있다.
물론 빌더 패턴이 최선의 방법이라고 찬양해서는 안된다. 어느 것이나 일장 일단이 있으니!
(TMI: 사실 나는 팀프로젝트 멘토님께 따로 조언 듣기 전에는 DTO객체에서도 setter 메서드를 절대적으로 지양했었다. 불변성이 제일 중요할 것이라고 생각 했기 때문에.. 그러나 어느정도 현업에서 수정이 잦은 필드에만 @Setter를 쓰기도 하고 동시에 여러개의 필드를 수정해야할 경우 setter 메서드를 생성하는 것이 더 좋을 때도 있다는 조언을 듣기도 했었다.. 알다가도 모를 개발의 규칙.. ㅎ..ㅎ)
Builder Pattern의 장단점
빌더 패턴의 장단점은 다음과 같다.
장점
- 코드를 더 깔끔하고 관리하기 쉽게 만드는데 도움이 됨.
- 어느 필드에 어느 값을 넣는지 명확하게 확인 할 수 있음.
- setter로 값을 지정하는 것이 아니라 불변성 보장함.
- 객체를 생성할 때 한번에 생성하므로 객체 일관성이 깨지지 않음.
- 새 기능과 설정 방법만 추가하면 되고 코드의 다른 부분을 변경하거나 수정할 필요가 없음.
단점
- 객체를 생성하기 위해 빌더 객체를 추가로 생성해야 하므로 오버헤드가 발생할 수 있음.
- 일부 필드의 값을 안넣어도 필드가 null로 들어가면서 객체가 생성가능함 ( -> Builder 클래스를 만들 때 필수적인 필드값을 넣어야 생성하는 패턴으로 어느정도 해결이 되긴 된다.)
Builder 어노테이션(@Builder)
사실 스프링에서 lombok을 통해 이 빌더 패턴을 쉽게 이용할 수 있다.
@Builder
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
public static void main(String[] args) {
House myhouse = new House.builder()
.rooms(3)
.toilets(2)
.windows(3)
.floors(2)
.hasBalcony(false)
.hasBackyard(false)
.build();
}
}
이렇게 클래스 위에 Builder 어노테이션을 사용해도 되고 특정 필드만 빌더패턴으로 구현하고 싶다면 생성자를 따로 만들어 놓고 그 위에만 Builder 어노테이션을 사용하면 된다.
'CS > 디자인패턴' 카테고리의 다른 글
[Design Pattern] Strategy Pattern(전략 패턴) (0) | 2024.06.02 |
---|---|
[Design Pattern] Factory Pattern(팩토리 패턴) (0) | 2024.06.01 |
[Design Pattern] Singleton Pattern(싱글톤 패턴) (0) | 2024.05.31 |
[Design Pattern] Observer pattern(옵저버 패턴) (0) | 2024.01.24 |
[Design Pattern] 디자인 패턴이란? (0) | 2024.01.23 |
Builder Parttern이란?
Builder Pattern은 디자인 패턴의 종류(생성, 구조, 행동) 중 생성 디자인 패턴에 속한다.
객체를 만드는 방법이 여러 가지 일때, 즉 옵션이 많은 객체를 만들어야할 때 사용함
Builder Pattern을 쓰는 이유 (== 기존 개발 형태에 대한 문제점)?
만일 집(아파트가 아닌 독립 주택)이라는 클래스가 있다고 하자.
해당 집에는 지붕, 방, 창문, 화장실, 마당, 발코니 등 여러 요소가 있고 할때 이를 클래스로 구현하면 다음과 같다.
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
}
이 클래스의 객체를 생성하기 위해서는 기존에는 두가지 방법으로 구현했다.
1. 점층적 생성자 패턴
2. 자바 빈즈 패턴
1. 점층적 생성자 패턴
이름 그대로 여러 개의 필드가 있을 때 점층적으로 생성자를 만들어두는 방법이다.
점층적 생성자 패턴은 다음과 같다.
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
public House(int rooms, int toilets, int windows) {
this.rooms = rooms;
this.rooms = toilets;
this.windows = windows;
}
public House(int rooms, int toilets, int windows, int floors) {
this.rooms = rooms;
this.rooms = toilets;
this.windows = windows;
this.floors = floors;
}
public House(int rooms, int toilets, int windows, int floors, boolean hasBalcony) {
this.rooms = rooms;
this.rooms = toilets;
this.windows = windows;
this.floors = floors;
this.hasBalcony = hasBalcony;
}
public House(int rooms, int toilets, int windows, int floors, boolean hasBalcony, boolean hasBackyard) {
this.rooms = rooms;
this.rooms = toilets;
this.windows = windows;
this.floors = floors;
this.hasBalcony = hasBalcony;
this.hasBackyard = hasBackyard;
}
}
이런 점층적 생성자 패턴을 이용해 House 클래스를 인스턴스화 해보자.
public static void main(String[] args) {
House myhouse = new House(3, 2, 3, 2, false, false);
}
필드(프로퍼티)가 많을 때 가독성이 떨어진다. 앞에 나와있는 3이 무슨 필드였고 뒤에 나오는 false들이 무슨 필드를 뜻하는지 외우지 않는 이상 알기가 어렵다.
또한 House 클래스에 필드를 추가할때 별도로 생성자를 만들거나 수정해줘야 null 값이 없는 완전한 객체를 만들 수 있다.
2. 자바 빈즈 패턴
이 패턴은 앞서 점층적 생성자 패턴과 달리 매개변수가 없는 생성자로만 객체를 만든 후, setter 메서드를 호출해 원하는 매개변수의 값을 설정하는 방법이다.
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
public House() {}
public void setRooms(int rooms) {
this.rooms = rooms;
}
public void setToilets(int toilets) {
this.toilets = toilets;
}
public void setWindows(int windows) {
this.windows = windows;
}
public void setFloors(int floors) {
this.floors = floors;
}
public void setHasBalcony(boolean hasBalcony) {
this.hasBalcony = hasBalcony;
}
public void setHasBackyard(boolean hasBackyard) {
this.hasBackyard = hasBackyard;
}
public static void main(String[] args) {
House myhouse = new House();
myhouse.setRooms(3);
myhouse.setToilets(2);
myhouse.setWindows(3);
myhouse.setFloors(2);
myhouse.setHasBalcony(false);
myhouse.setHasBackyard(false);
}
}
자바 빈즈 패턴을 사용하면 이전 점층적 생성자 패턴보다는 어떤 필드 값에 어떤 값을 가지는지 조금 명확해졌지만 setter 메서드로 인해 불변성이 깨진다는 것이 단점이다.
Builder Pattern(빌더 패턴) 구현 방법
빌더 패턴은 Builder 클래스를 별도로 만들어주면 된다.
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
public static class HouseBuilder {
private House house;
public HouseBuilder() {
this.house = new House();
}
public HouseBuilder rooms(int rooms) {
this.house.rooms = rooms;
return this;
}
public HouseBuilder toilets(int toilets) {
this.house.toilets = toilets;
return this;
}
public HouseBuilder windows(int windows) {
this.house.windows = windows;
return this;
}
public HouseBuilder floors(int floors) {
this.house.floors = floors;
return this;
}
public HouseBuilder hasBalcony(boolean hasBalcony) {
this.house.hasBalcony = hasBalcony;
return this;
}
public HouseBuilder hasBackyard(boolean hasBackyard) {
this.house.hasBackyard = hasBackyard;
return this;
}
public House build() {
return this.house;
}
}
public static void main(String[] args) {
House myhouse = new HouseBuilder()
.rooms(3)
.toilets(2)
.windows(3)
.floors(2)
.hasBalcony(false)
.hasBackyard(false)
.build();
}
}
우리는 이 빌더 패턴으로 점층적 생성자 패턴과 같이 불변성을 보장할 수 있고, 자바 빈즈 패턴처럼 어떤 필드에 어떤 값을 가지는지 가독성을 높일 수 있다. 그리고 추가적으로 체이닝기법을 사용해서 연속적으로 쓸 수 있다.
물론 빌더 패턴이 최선의 방법이라고 찬양해서는 안된다. 어느 것이나 일장 일단이 있으니!
(TMI: 사실 나는 팀프로젝트 멘토님께 따로 조언 듣기 전에는 DTO객체에서도 setter 메서드를 절대적으로 지양했었다. 불변성이 제일 중요할 것이라고 생각 했기 때문에.. 그러나 어느정도 현업에서 수정이 잦은 필드에만 @Setter를 쓰기도 하고 동시에 여러개의 필드를 수정해야할 경우 setter 메서드를 생성하는 것이 더 좋을 때도 있다는 조언을 듣기도 했었다.. 알다가도 모를 개발의 규칙.. ㅎ..ㅎ)
Builder Pattern의 장단점
빌더 패턴의 장단점은 다음과 같다.
장점
- 코드를 더 깔끔하고 관리하기 쉽게 만드는데 도움이 됨.
- 어느 필드에 어느 값을 넣는지 명확하게 확인 할 수 있음.
- setter로 값을 지정하는 것이 아니라 불변성 보장함.
- 객체를 생성할 때 한번에 생성하므로 객체 일관성이 깨지지 않음.
- 새 기능과 설정 방법만 추가하면 되고 코드의 다른 부분을 변경하거나 수정할 필요가 없음.
단점
- 객체를 생성하기 위해 빌더 객체를 추가로 생성해야 하므로 오버헤드가 발생할 수 있음.
- 일부 필드의 값을 안넣어도 필드가 null로 들어가면서 객체가 생성가능함 ( -> Builder 클래스를 만들 때 필수적인 필드값을 넣어야 생성하는 패턴으로 어느정도 해결이 되긴 된다.)
Builder 어노테이션(@Builder)
사실 스프링에서 lombok을 통해 이 빌더 패턴을 쉽게 이용할 수 있다.
@Builder
public class House {
private int rooms;
private int toilets;
private int windows;
private int floors;
private boolean hasBalcony;
private boolean hasBackyard;
public static void main(String[] args) {
House myhouse = new House.builder()
.rooms(3)
.toilets(2)
.windows(3)
.floors(2)
.hasBalcony(false)
.hasBackyard(false)
.build();
}
}
이렇게 클래스 위에 Builder 어노테이션을 사용해도 되고 특정 필드만 빌더패턴으로 구현하고 싶다면 생성자를 따로 만들어 놓고 그 위에만 Builder 어노테이션을 사용하면 된다.
'CS > 디자인패턴' 카테고리의 다른 글
[Design Pattern] Strategy Pattern(전략 패턴) (0) | 2024.06.02 |
---|---|
[Design Pattern] Factory Pattern(팩토리 패턴) (0) | 2024.06.01 |
[Design Pattern] Singleton Pattern(싱글톤 패턴) (0) | 2024.05.31 |
[Design Pattern] Observer pattern(옵저버 패턴) (0) | 2024.01.24 |
[Design Pattern] 디자인 패턴이란? (0) | 2024.01.23 |