일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |
- algorithm
- java
- 코드스쿼드
- 알고리즘데이
- SWEA
- 쉽게 배우는 운영체제
- baekjoon1541
- 2021.01.11
- spring-boot
- 2021.01.22
- 2021.01.14
- 2020.01.08
- 마스터즈 2주차 회고
- Til
- 백준
- 알고리즘
- 백준 9093
- 2021.01.21
- 2021.01.18
- 2021.01.06
- 백준 1149
- 2021.01.13
- 자바
- 박재성
- 잃어버린 괄호
- 2021.01.19
- 괄호
- 코드스쿼드 마스터즈
- 2021.01.12
- 2021.01.17
- Today
- Total
Cooper's devlog
빌더 패턴(builder) 맛보기 본문
[자바 공부를 하며 빌드 패턴 공부하며 정리하는 글입니다. 참고용으로 봐주시고 피드백은 언제나 환영입니다!]
저는 주로 인스턴스를 생성할 때는 주로 점층적 생성자 패턴 혹은 자바빈즈 패턴을 주로 사용했습니다. 빌드 패턴을 이야기 하기전에 에 점층적 생성자 패턴과 자바 빈즈 패턴은 무엇일까요?
1. 점층적 생성자 패턴(Telescoping constructor Pattern)
- 정의 : 선택 매개변수를 전부 다 받는 생성자끼리 늘려가는 방식
이렇게 말로만 보면 어떤 의미인지 와닿지 않으니 코드를 통해서 확인해보도록 하겠습니다!
public class StudentScore {
private final String studentId;
private final int kor;
private final int math;
private final int eng;
private final int sci;
public ExamScores(int kor, int math) {
this(kor, math, 0, 0);
}
public ExamScroes(int kor, int math, int eng) {
this(kor, mat, eng, 0);
}
public ExamScores(int kor, int math, int eng, int sci) {
this.kor = kor;
this.math = math;
this.eng = eng;
this.sci = sci;
}
}
위에 정의부분 말그래도 선택 매개변수를 전부 다 받는 생성자를 늘려가는 방식을 점층적 생성자 패턴이라고 부릅니다. 아마 자바 문법책에 나오는 형태가 주로 점층적 생성자 패턴이라고 생각하시면 됩니다.
하지만 점층적 생성자 패턴에는 단점이 존재하게 되는데,
- 확장하기가 어렵다.
- 매개변수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다.
- 클라이언트가 실수로 매개변수 순서를 바꿔 컴파일러가 인지하지 못하는 경우가 발생한다.
인스턴스를 생성하고자 하는 경우, 매개변수의 위치가 변경되면 아마 찾는데는 엄청난 시간이 소요될지도 모릅니다. 사실 저도 같은 경험을 하며 좀 더 좋은 방법을 찾고자 이 글을 작성한 것이기도 하구요.
혹시 더욱 좋은 방법이 있을지도 모르니 다른 방법을 한번 찾아보도록 하겠습니다.
2. 자바빈즈 패턴(JavaBeans Pattern)
- 정의 : 객체를 생성한 후, 세터(setter) 메서드를 호출해 원하는 매개변수의 값을 설정하는 방식.
아마 객체지향으로 코드를 조금 작성해보신 분들이라면 class정의 시, getter와 setter에 대해 경험해보셨을 것으로 생각합니다. 자바빈즈 패턴은 setter를 사용하는 방법입니다.
public class StudentScores {
private String studentId;
private int kor = 0;
private int math = 0;
private int eng = 0;
private int sci = 0;
public void setStudentId(String studentId) {
this.studentId = studentId;
}
public void setKor(int kor) {
this.kor = kor;
}
public void setMath(int math) {
this.math = math;
}
public void setEng(int eng) {
this.eng = eng;
}
public void setSci(int sci) {
this.sci =sci;
}
}
이와 같이 인스턴수에 해당하는 변수들을 setter를 이용해서 값을 초기화하는 패턴을 자바빈즈패턴(JavaBeans Pattern)이라고 합니다. 하지만JavaBeans 패턴에도 단점이 존재합니다.
- 일관성이 무너진다.
- 하나의 객체 완성을 위해서는 많은 메서드(setter) 호출이 필요하다.
- 코드가 물리적으로 떨어져 있는 경우, 디버깅이 어렵다.
- 클래스를 불변으로 만들 수었다.
일관성이 무너진다는 이야기는 한번 객체를 생성할 때, 그 객체가 변할 여지가 존재한다는 것입니다. 또한 객체가 완성되기 전까지는 값들이 완성이 되기 전까지 일관성이 무너진 상태에 놓이게 됩니다.
예를 들자면 코드에서 kor, math, eng 모두 설정한 상태에서 갑자기 프로그램이 비정상적으로 종료가 된다면 sci값은 설정되지 않는 상태에 놓입니다. 객체는 생성되었지만 완전한 객체가 아니기 때문에 이후 버그의 원인이 될 수도 있습니다.
3. 빌드 패턴(Builder Pattern)
아마 예상하셨듯이 빌드패턴은 이전의 점증적 생성자 패턴과 자바 빈즈 패턴의 단점을 모두 보완할 수 있는 방법입니다.
우선 빌드 패턴의 방법부터 먼저 알아보겠습니다.
- 필수 매개변수만 우선 생성자 혹은 정적 메서드를 호출해 빌더 객체를 얻는다.
- 선택 매개변수는 빌더 객체가 제공하는 일종의 세터 메서드를 사용한다.
public class StudentScores {
private final String studentId;
private final int kor;
private final int math;
private final int eng;
private final int sci;
public static class Builder {
//필수 매개인자
private final String studentId;
//선택 매개인자
private int kor = 0;
private int math = 0;
private int eng = 0;
private int sci = 0;
public Builder(String studenId) {
this.studentId = studentId;
return this;
}
public Builder kor(int val) {
this.kor = val;
return this;
}
public Builder math(int val) {
this.math = val;
return this;
}
public Builder eng(int val) {
this.eng = val;
return this;
}
public Builder sci(int val) {
this.sci = val;
return this;
}
public StudentScores build() {
return studentScore(this);
}
}
private StudentScore(Builder builder) {
studentId = builder.studentId;
kor = builder.kor;
math = builder.math;
eng = builder.eng;
sci = builder.sci;
}
}
처음 접하시는 분들은 굉장히 생소하실 겁니다. 사실 저도 아직 많이 생소합니다ㅠ
일단 코드를 확인해보시면 내부에 Builder를 정적 클래스로 선언했습니다. 그리고 내부에 있는 값들을 setter형식으로 처리되지만 return type을 Builder로 설정했습니다. 그리고 모든 값을 설정하면 build를 통해 값을 초기화 할 수 있는 것입니다.
builder패턴은 위에서 말씀드린 것과 같이 두가지 단점을 보완할 수 있습니다.
1. 일관성을 유지할 수 있다는 점입니다.
기존의 자바빈즈 패턴은 객체가 완성되는 시점을 파악하기도 어려웠습니다. 하지만 builder pattern을 사용하면 객체 완성 시점을 확실히 파악할 수 있다는 장점이 있습니다. 또한 물리적으로 코드가 멀어질 일이 없어 디버깅을 하는데 있어서 훨씬 수월합니다.
2. 코드의 가독성이 좋아지고 실수를 줄일 수 있다.
일단 builder pattern을 사용했을 때의 인스턴스 생성 코드를 보겠습니다.
//점층적 생성자 패턴(telescoping constructor patten)
StudentScores cooper = new StudentScores("cooper", 80, 100, 90, 100);
//빌더 패턴(builder pattern)
StudentScores cooper = new StudentScores.Builder(("cooper"))
.kor(80)
.math(100)
.eng(90)
.sci(100)
.build();
두 코드를 비교해보면 확연히 빌더 패턴의 코드가 읽기 편한 것을 확인할 수 있습니다. 어디에 어떤 값들이 들어갔는지 확인하기 어려운 점층자 생성자에 비해 훨씬 확인하기 편리하기까지 합니다.
빌더패턴을 보면 메서드를 연속적으로 이어나가는 방식을 채택하고 있는데 이 방식을 메서드 연쇄(method chaining)이라고 하네요!
[마치며]
공부한 내용을 정리하는 목적이라 정확하지 않은 부분과 설명이 빈약한 부분이 있습니다. 하지만 조금이나마 코딩하는데 있어서 한번쯤은 고려하셔서 빌더패턴을 한번 사용해보시는 것도 좋을 것 같습니다.
부족한 글 봐주셔서 감사합니다!