티스토리 뷰

// Boolean 클래스의 valueOf 메서드
public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

👍 정적 팩터리 메서드가 생성자보다 좋은 장점

1. 이름을 가질 수 있다.

이름만 잘 지으면 반환될 객체의 특성을 쉽게 묘사할 수 있다.
예) BigInteger(int, int, Random) vs BigInteger,probablePrime 후자가 소수인 BigInteger를 반환한다는 의미를 더 잘 설명한다.

2. 호출될 때마다 인스턴스를 새로 생성하지 않아도 된다.

(1) 자주 생성될 것 같은 객체는 미리 만들어 놓고 재사용하여 불필요한 객체 생성을 피할 수 있다.
(2) 언제 어느 인스턴스를 살아있게 할지 통제할 수 있다. (인스턴스 통제 클래스)
싱글턴 / 인스턴스화 불가 / 불변 값 클래스에서 동치인 인스턴스가 단 하나뿐임을 보장

3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.

interface Noodle {
    public static KongGookSoo kongGookSoo() {
        return new KongGookSoo();
    }

    public static Calcox calcox() {
        return new Calcox();
    }

    public static ZzaZangMyeon zzaZangMyeon() {
        return new ZzaZangMyeon();
    }
}

class KongGookSoo implements Noodle {
    // ..
}

class Calcox implements Noodle{
    // ..
}

class ZzaZangMyeon implements Noodle {
    // ..
}

Java8부터는 인터페이스가 static 메소드를 가질 수 있게 되었다.
구현 클래스를 공개하지 않고도 객체를 반환할 수 있다.

4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.

예) EnumSet 클래스는 원소의 수에 따라 두 가지 하위클래스 중 하나의 인스턴스를 반환한다.
(1) 원소 64개 이하 : long변수로 원소를 관리하는 RegularEnumSet
(2) 원소 65개 이상 : long배열로 원소를 관리하는 JunboEnumSet
클라이언트는 이 두 클래스의 존재를 모른다.

5. 정적 팩터리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.

👎 정적 팩터리 메서드의 단점

1. 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.

상속을 하려면 public, protected 생성자가 필요하기 때문에, 생성자 대신 정적 팩터리 메서드만 제공한다면 상속받은 하위 클래스를 만들 수 없다.

2. 프로그래머가 찾기 어렵다.

정적 팩터리 메서드는 그냥 메서드이기 때문에, Javadoc에서 생성자처럼 쉽게 찾기 어려울 수도 있다.
이 단점을 보완하기 위해서, 알려진 규약대로 이름을 지어줄 수 있다.

(1) from: 매개변수를 하나 받아서 해당 타입의 인스턴스를 반환하는 형변환 메서드
Date d = Date.from(instant);
(2) of: 여러 매개변수를 받아 적합한 타임의 인스턴스를 반환하는 집계 메서드
Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
(3) valueOf: from과 of의 더 자세한 버전
BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
(4) instance or getInstance: 매개변수로 명시한 인스턴스를 반환하지만, 같은 인스턴스임을 보장하지는 않는다.
StackWalker luke = StackWalker.getInstance(options);
(5) create or newInstance: instance혹은 getInstance와 같지만, 매번 새로운 인스턴스를 생성해 반환함을 보장한다.
Object newArray = Array.newInstance(classObject, arrayLength);
(6) getType: getInstance와 같지만, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다.
FileStore fs = Files.getFileStore(path);
(7) newType: newInstance와 같지만, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 쓴다.
BufferedReader br = Files.newBuferedReader(path);
(8) type: getType과 newType의 간결한 버전
List<Complaint> litany = Collections.list(legacyLitany);