Meet-Coder-Study / book-effective-java

📔 이펙티브 자바 스터디 저장소

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

아이템1. 생성자 대신 정적 팩터리 메서드를 고려하라

ksy90101 opened this issue · comments

9페이지 4번째 문단 끝에

인스턴스 통제는 플라이웨이트 패턴의 근간이 되며, 열거 타입은 인스턴스가 하나만 만들어짐을 보장한다.
라는 내용에서

정적 팩터리 메서드를 통한 인스턴스 통제와 열거 타입의 인스턴스 통제는 성격이 달라 보이는데 다른분들은 어떻게 생각하시나요??

여기서 말하는 인스턴스 통제는 반복되는 요청에 같은 객체를 반환하는 식이라고 합니다.

public static final BigInteger ZERO = new BigInteger(new int[0], 0);

private final static int MAX_CONSTANT = 16;
private static BigInteger posConst[] = new BigInteger[MAX_CONSTANT+1];
private static BigInteger negConst[] = new BigInteger[MAX_CONSTANT+1];

static {
    /* posConst에 1 ~ 16까지의 BigInteger 값을 담는다. */
    /* negConst에 -1 ~ -16까지의 BigInteger 값을 담는다. */
}

public static BigInteger valueOf(long val) {
    // 미리 만들어둔 객체를 리턴한다
    if (val == 0)
        return ZERO;
    if (val > 0 && val <= MAX_CONSTANT)
        return posConst[(int) val];
    else if (val < 0 && val >= -MAX_CONSTANT)
        return negConst[(int) -val];

    // 새로운 객체를 만들어 리턴한다
    return new BigInteger(val);
}

확실하지는 않지만 위의 코드처럼 새로운 객체를 리턴할수도 있지만, 원래 있는 객체(즉, 싱글턴)로도 정적팩토리를 사용할 수 있다는 의미같아요.
여기서 나오는 특징이 2. 호출될 떄마다 인스턴스를 새로 생성하지는 않아도 된다.인데, 그에 대한 예제가 위에 있는 코드이거든요 ㅎㅎ
그렇다면 enum을 사용하거나, 정적 팩토리 메서드를 위와 같이 사용하거나 동일하지 않을까요?(하나 다른점은 새로운 객체를 만들어 리턴하는 부분만?)
답변이 잘 되었는지 모르겠네요 :)

@ksy90101
답변감사합니다 👍 결국 반복되는 요청에 같은 객체를 반환한다는 점에서 같군요.

그런데 정적 팩터리 메서드는 static메서드를 통해 인스턴스를 반환을 조절함으로써 인스턴스를 통제하지만
enum은 컴파일 타임에 인스턴스를 생성해 두고, 생성자를 private으로 감추는 것으로 인스턴스를 통제하기 때문에

통제하는 방식이 조금 다른 거라고 보면 되겠군요.

commented

정적 팩터리 메서드를 통한 인스턴스 통제와 열거 타입의 인스턴스 통제는 성격이 달라 보이는데 다른분들은 어떻게 생각하시나요?? 이 질문에 대한 답으로 item3. private 생성자나 열거 타입으로 싱글턴임을 보증해라 파트의 내용이 도움이 될 것 같습니다.

두 분이 말씀하신 내용에 덧붙여 두 가지 방법이 인스턴스 통제하는 방식에서 어떤 차이점이 있는지 조금 더 자세히 나와있습니다.

여기서 소개하는 세 가지 방식 중

  1. 정적 팩터리 방식으로 인스턴스를 통제하는 방법
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }

    public void leaveTheBuilding() { ... }
}
  1. 원소가 하나인 열거 타입을 선언하는 방법
public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() { ... }
}

이 두가지의 내용을 살펴보면 둘다 인스턴스를 통제한다는 점에서는 동일하지만, 정적 팩터리 방식은 직렬화를 역직렬화할 때 가짜 객체가 생성되어 인스턴스 통제가 안될 수 있지만 열거 타입을 사용하면 간결한 방식으로 직렬화가 가능하며 인스턴스 통제가 가능하다고 합니다.

(물론 정적 팩터리 방식도 readResolve메서드와 transient를 이용해서 인스턴스 통제를 할 수 있지만, item89에서 직렬화를 할 경우 정적팩터리 방식보다 enum을 추천하고 있습니다.)