📖본 포스팅은 'Effective java - 조슈아' 님의 책을 보고 작성되었습니다.
[점층적 생성자 패턴(Telescoping Constructor Pattern)]
- 필수 매개변수만 받는 생성자부터 ~ 필수 매개변수 + 선택 매개변수 1 ... n개 전부 다 받는 생성자까지 모든 생성자를 작성하는 방법
[점층적 생성자 패턴 예시 코드]
public class NutritionFacts{
private final int servingSize; // 필수
private final int servings; // 필수
private final int calories; // 선택
private final int fat; // 선택
private final int sodium; // 선택
private final int carbohydrate; // 선택
public NutritionFacts(int servingSize, int servings){
this(servingSize, servings, 10);
}
public NutritionFacts(int servingSize, int servings, int calories){
this(servingSize, servings, calories, 0);
}
public NutritionFacts(int servingSize, int servings, int calories,
int fat){
this(servingSize, servings, calories, fat, 0);
}
public NutritionFacts(int servingSize, int servings, int calories,
int fat, int sodium){
this(servingSize, servings, calories, fat, sodium, 0);
}
public NutritionFacts(int servingSize, int servings, int calories,
int fat, int sodium, int carbohydrate){
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.sodium = sodium;
this.carbohydrate = carbohydrate;
}
}
- 점층적 생성자 패턴을 사용할 때 원하는 인스턴스 생성을 위해서는 원하는 매개변수를 모두 포함하고 있는 생성자 중 가장 짧은 것을 골라서 호출해주면 된다.
[점층적 생성자 패턴 장점]
- 원하는 매개변수를 모두 포함한 생성자 중 가장 짧은 것을 호출하면 된다.
[점층적 생성자 패턴 단점]
- 점층적 생성자 패턴은 선택적 매개변수가 많아지면 적절한 대응이 어려워진다.
- 또한 매개변수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다.
[자바빈즈 패턴(JavaBeans Pattern)]
- 점층적 생성자 패턴의 단점을 해결하고자 자바빈즈 패턴을 사용해보았다.
- 자바빈즈 패턴은 매개변수가 없는 생성자로 객체를 만든 뒤, Setter 메서드를 통한 매개변수 값을 설정하는 방식이다.
[자바빈즈 패턴 예시 코드]
class NutritionFacts{
private int servingSize = -1; //필수
private int servings = -1; //필수
private int calories = 0; //필수
private int fat = 0; //필수
private int sodium = 0; //필수
private int carbohydrate = 0; //필수
//참고: 생성자는 리턴값이 없지만 void를 사용하지 않는다.
public NutritionFacts() {} //매개변수 없는 생성자로 객체 생성
//Setter 메서드를 통한 매개변수 값 설정.
public void setServingSize(int servingSize) {
this.servingSize = servingSize;
}
public void setServings(int servings) {
this.servings = servings;
}
public void setCalories(int calories) {
this.calories = calories;
}
public void setFat(int fat) {
this.fat = fat;
}
public void setSodium(int sodium) {
this.sodium = sodium;
}
public void setCarbohydrate(int carbohydrate) {
this.carbohydrate = carbohydrate;
}
}
[자바빈즈 패턴 호출]
NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);
[자바빈즈 패턴의 장점]
- 코드가 길어지긴 하지만 인스턴스를 만들기 쉬워지고 결과적으로는 더 읽기 쉬운 코드가 된다.
[자바빈즈 패턴의 단점]
- 객체 하나를 만들기 위해 여러 개의 메서드를 호출해야 하고, 객체가 완전히 생성되기 전까지 일관성이 무너진 상태에 놓이게 된다.
- 클래스를 불변으로 만들 수 없고 스레드 안전성을 얻으러면 프로그래머가 추가 작업을 진행해야 한다.
- 생성이 끝난 객체를 수동으로 freezing하기 전에는 사용할 수 없게 하여서 자바빈즈 패턴의 단점을 보완해보려 시도했다.
- 그러나 이 방법은 다루기 어렵다
- 또한 프로그래머가 freeze 메서드를 확실히 호출했는지 컴파일러의 보증이 없기 때문에 런타임 오류에 매우 취약하다(런타임 에러는 에러를 잡는 것이 매우 어렵다.)
[빌더 패턴(Builder Pattern)]
- 빌더 패턴? 점층적 생성자 패턴의 안정성 + 자바빈즈 패턴의 가독성
- 클라이언트
- 필요한 객체를 직접 만들지 않고 필수 매개변수만으로 생성자를 호출한 뒤 빌더 객체를 얻는다.
- 그 후 빌더 객체가 제공하는 일종의 Setter 메서드들로 원하는 선택 매개변수들을 설정한다.
- 마지막으로 매개변수가 없는 build 메서드를 통해 우리에게 필요한 객체를 얻는다.
[빌더 패턴 예시 코드]
class NutritionFacts{
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder{
// 필수 매개변수
private final int servingSize;
private final int servings;
// 선택 매개변수
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrate = 0;
//필수 매개변수만으로 생성자를 호출해 빌더 객체를 얻음
public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
}
//Setter 메서드들을 사용해 원하는 선택 매개변수를 설정
public Builder calories(int calories){
this.calories = calories;
return this;
}
public Builder fat(int fat){
this.fat = fat;
return this;
}
public Builder sodium(int sodium){
this.sodium = sodium;
return this;
}
public Builder carbohydrate(int carbohydrate){
this.carbohydrate = carbohydrate;
return this;
}
//매개변수가 없는 build 메서드를 사용하여 우리에게 필요한 객체를 얻는다.
public NutritionFacts build(){
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder){
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
}
[빌더 패턴의 특징]
- NutritionFacts 클래스는 불변이고 모든 매개변수의 기본값들을 한곳에 모아 둔다.
- 빌더의 Setter 메서드들은 빌더 자신을 반환하기 때문에 연쇄적인 호출이 가능하다.
[빌더 패턴의 인스턴스 생성]
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
.calories(100)
.sodium(35)
.carbohydrate(27).build();
- 빌더 패턴 코드는 쓰기 쉽고, 읽기도 쉽다. 계층적으로 설계된 클래스와 함께 사용하면 더 좋다.
[빌더 패턴과 계층적 클래스를 사용한 방법]
추후에 정리...
[핵심]
- 생성자나 정적 팩토리가 처리해야 할 변수가 많다면 빌더 패턴을 고려하자
- 점층적 생성자보다 코드를 읽고 쓰기가 간결하다.
- 자바빈즈보다 훨씬 안전하다.
'Java > 이펙티브 자바(Effective Java)' 카테고리의 다른 글
[이펙티브 자바(Effective Java)][객체 생성과 파괴] - 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.04.08 |
---|---|
[이펙티브 자바(Effective Java)][객체 생성과 파괴] - 4. 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2022.04.08 |
[이펙티브 자바(Effective Java)][객체 생성과 파괴] - 3. 생성자나 열거타입으로 싱글턴 임을 보증하라 (0) | 2022.04.08 |
[이펙티브 자바(Effective Java)][객체 생성과 파괴] - 1. 생성자 대신 정적 팩터리 메서드를 고려해라 (0) | 2022.04.04 |
[이펙티브 자바(Effective Java)] - 0. 들어가기에 앞서 (0) | 2022.04.04 |