Study-Mornda / Effective-Java

'Effective Java 3/E' 스터디 저장소입니다.
3 stars 0 forks source link

[아이템 2] 생성자에 매개변수가 많다면 빌더를 고려하다 #2

Closed riyenas0925 closed 2 years ago

riyenas0925 commented 3 years ago

아이템 : 생성자에 매개변수가 많다면 빌더를 고려하다

kimhanui commented 3 years ago

16pg

"자바빈즈패턴에서는 객체 하나를 만들려면 메서드를 여러 개 호출해야 하고, 객체가 완전히 생성되지 전까지는 일관성(consistency)이 무너진 상태에 놓이게 된다."에서 일관성의 의미? :

문단 아래 쪽의 "자바빈즈 패턴에서는 클래스를 불변으로 만들 수 없으며 스레드 안정성을 얻으려면 프로그래머가 추가 작업을 해줘야만 한다."를 봤을 때 자바빈즈패턴은 스레드 안정적인 패턴이 아님을 알 수 있음.

=> 즉, setter가 있으면 언제든지 값을 바꿀 수 있으므로 멀티 쓰레딩 환경에서 값의 유효성을 보장하지 못한다는 뜻인 것 같다.

riyenas0925 commented 3 years ago

19pg 불변 : 어떠한 변경도 허용하지 않는다는 걸 의미

불변식 : 프로그램이 실행되는 동안, 혹은 정해진 기간 동안 반드시 만족해야 하는 조건을 의미

riyenas0925 commented 3 years ago

pg18

NutritionFacts 클래스는 왜 불변인가?

Immutable Class

Immutable Class 장단점

장점

단점

kimhanui commented 3 years ago

20pg

public abstract class Pizze{
  // ..
  abstract static class Builder<T extends Builder<T>> { ... }
  // ..
}

에서 "재귀적 타입 한정" 이란? :
Builder<T extends Builder<T>> 에서 T가 자신을 포함하는 수식 Builder에 의해 한정(bound)되는 것. 여기선

cheewr85 commented 2 years ago

[질문] 16~17pg 자바 빈즈 패턴에서 일관성 이슈는 위의 질문-답변에서 해결 여기서 추가적으로 이를 완화하고자 freeze 메서드를 통해서 완화를 한다고 했는데 어떤 방식으로 하는것인지? 이게 어떤 측면에서 컴파일러가 보증할 방법이 없는것인지? 그래서 안 쓰이게 되는 부분이 무엇인지?

cheewr85 commented 2 years ago

[질문] 18pg 빌더패턴에서 유효성 검사 코드는 생략했다고 했는데, 이 부분까지 확실히 추가해줘야하는 것인지 추가한다면 어떻게 추가해서 유효성 검사를 하는지 궁금함

cheewr85 commented 2 years ago

[질문] 20pg 재귀적 타입 한정 위의 질문에서 개념과 코드적으로 설명했는데 좀 더 들어가서 제너릭 타입이 어떻게 작용되면서 쓰이는지 그리고 제너릭 타입에 대해서 다른 예시와 함께 구체적인 정의를 다시 짚고 넘어가고 싶음(제너릭 부분이 좀 애매하게 이해됨)

cheewr85 commented 2 years ago

[질문] 20pg 책에서 설명한 시뮬레이트한 셀프 타입에 대해서 좀 더 추가적인 예시가 궁금함, 책에 설명과 덧붙여서

cheewr85 commented 2 years ago

[질문] 21pg 공변 반환 타이핑에 대한 추가적인 예시와 책에서 말한 정의를 좀 더 구체화해서 짚고 넘어가고 싶음

cheewr85 commented 2 years ago

[질문] 16~17pg 자바 빈즈 패턴에서 일관성 이슈는 위의 질문-답변에서 해결 여기서 추가적으로 이를 완화하고자 freeze 메서드를 통해서 완화를 한다고 했는데 어떤 방식으로 하는것인지? 이게 어떤 측면에서 컴파일러가 보증할 방법이 없는것인지? 그래서 안 쓰이게 되는 부분이 무엇인지?

cheewr85 commented 2 years ago

[질문] 18pg 빌더패턴에서 유효성 검사 코드는 생략했다고 했는데, 이 부분까지 확실히 추가해줘야하는 것인지 추가한다면 어떻게 추가해서 유효성 검사를 하는지 궁금함

TargetObject build() {
    TargetObject res = new TargetObject();
    res.setProperty1();
    res.setProperty2();
    validate(res); // This call may throw an exception
    return res;
}

void validate(TargetObject obj) {
    if (...) {
        throw new IllegalStateException();
    }
}
TargetObject build() {
    TargetObject res = new TargetObject();
    res.setProperty1();
    res.setProperty2();
    if (...) {
        throw new IllegalStateException();
    }
    return res;
}
cheewr85 commented 2 years ago

[질문] 20pg 재귀적 타입 한정 위의 질문에서 개념과 코드적으로 설명했는데 좀 더 들어가서 제너릭 타입이 어떻게 작용되면서 쓰이는지 그리고 제너릭 타입에 대해서 다른 예시와 함께 구체적인 정의를 다시 짚고 넘어가고 싶음(제너릭 부분이 좀 애매하게 이해됨)

public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) {
    int count = 0;
    for (T e : anArray)
        if (e.compareTo(elem) > 0)
            ++count;
    return count;

cheewr85 commented 2 years ago

[질문] 20pg 책에서 설명한 시뮬레이트한 셀프 타입에 대해서 좀 더 추가적인 예시가 궁금함, 책에 설명과 덧붙여서

public class NyPizza extends Pizza { public enum Size { SMALL, MEDIUM, LARGE } private final Size size;

public static class Builder extends Pizza.Builder { private final Size size;

  public Builder(Size size) {
     this.size = Objects.requireNonNull(size);
  }

  @Override public NyPizza build() {
     return new NyPizza(this);
  }

  @Override protected Builder self() { return this; }

}

private NyPizza(Builder builder) { super(builder); size = builder.size; } }

public class Calzone extends Pizza { private final boolean sauceInside;

public static class Builder extends Pizza.Builder { private boolean sauceInside = false;

  public Builder sauceInside() {
     sauceInside = true;
     return this;
  }

  @Override public Calzone build() {
     return new Calzone(this);
  }

  @Override protected Builder self() { return this; }

}

private Calzone(Builder builder) { super(builder); sauceInside = builder.sauceInside; } }


- 이러면 메서드 연쇄를 지원할 수 있다는 것인데 이는 아래와 같이 형변환을 생각하지 않고도 빌더를 사용하는 것을 의미함
```java
public class Main {
    public static void main(String[] args) {
        NYPizza pizza = new NYPizza.Builder(SMALL)
                .addTopping(SAUSAGE)
                .addTopping(ONION)
                .build();

        Calzone calzone = new Calzone.Builder()
                .addTopping(HAM)
                .sauceInside()
                .build();
    }
}
cheewr85 commented 2 years ago

[질문] 21pg 공변 반환 타이핑에 대한 추가적인 예시와 책에서 말한 정의를 좀 더 구체화해서 짚고 넘어가고 싶음

riyenas0925 commented 2 years ago

[질문] 21pg 공변 반환 타이핑에 대한 추가적인 예시와 책에서 말한 정의를 좀 더 구체화해서 짚고 넘어가고 싶음

공변 반환 타입 (Covariant return type)

Producer의 method에서 SuperType(Object) 리턴한다면, IntegerProducer에서 Override하는 method에서는 SubType(Integer)를 리턴해도 된다

public class Producer {
    public Object produce(String input) {
        Object result = input.toLowerCase(Locale.ROOT);
        return result;
    }
}
public class IntegerProducer extends Producer {
    @Override
    public Integer produce(String input) {
        return Integer.parseInt(input);
    }
}

Reference

https://www.baeldung.com/java-covariant-return-type

riyenas0925 commented 2 years ago

점층적 생성자 패턴(Telescoping Constructor pattern)

필수 매개변수만 받는 생성자, 필수 매개변수와 선택 매개변수 1개를 받는 생성자, 선택 매개변수를 2개까지 받는 생성자... 형태로 선택 매개변수를 전부다 받는 생성자까지 늘려가는 방식

매개변수가 많아지면 클라이언트 코드를 작성하거나 읽기 어렵다. 코드를 읽을 때 각 값의 의미가 불명확하고 타입이 같은 매개변수가 연달아 늘어서 있으면 찾기 어려운 버그로 이어질 수 있다.

 public 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;

    public NutritionFacts(int servingSize, int servings) {
        this(servingSize, servings, 0);
    }

    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;
    }
}
public class Main {
    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);
    }
}

자바 빈즈 패턴(JavaBeans pattern)

메개변수가 없는 생성자로 객체를 만든 후 setter 메서드를 호출해 원하는 매개변수의 값을 설정하는 방식

자바 빈즈 패턴에서는 객체 하나를 만들려면 메서드를 여러 개 호출해야 하고, 객체가 완전히 생성되기 전까지는 일관성(consistency)이 무너진 상태에 놓이게 된다. 이런 문제 때문에 자바빈즈 패턴에서는 클래스를 불변으로 만들 수 없으며 스레드 안정성을 얻으려면 프로그래머가 추가 작업을 해줘야 한다.

public 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;

    public NutritionFacts() {

    }

    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;
    }
}
public class Main {
    public static void main(String[] args) {
        NutritionFacts nutritionFacts = new NutritionFacts();
        nutritionFacts.setCalories(100);
        nutritionFacts.setServingSize(240);
        nutritionFacts.setServings(8);
        nutritionFacts.setSodium(35);
        nutritionFacts.setCarbohydrate(27);
    }
}
riyenas0925 commented 2 years ago

[질문] 18pg 빌더패턴에서 유효성 검사 코드는 생략했다고 했는데, 이 부분까지 확실히 추가해줘야하는 것인지 추가한다면 어떻게 추가해서 유효성 검사를 하는지 궁금함

https://stackoverflow.com/questions/38173274/builder-pattern-validation-effective-java