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

Jimin Lim·2022년 2월 19일
0

Effective Java

목록 보기
1/38
post-thumbnail

아이템 1

생성자 대신 정적 팩터리 메서드를 고려하라

인스턴스를 생성하는 방법은 (1)public 생성자, (2)정적 팩터리 메서드가 있다.

//(1) Public 생성자
public class Person {
	public Person() {
	}
}
//(2) 정적 팩터리 메서드
public class Person {
	private static Person PERSON = new Person();
    
	private Person() { // 외부 생성 금지를 위한 private
	}

	public static final Person getInstance() { 
		return PERSON;
	}
}

(1)보다 (2)방식이 좋은 장점은 다음과 같다.

1. 이름을 가질 수 있다.
생성자의 경우, 생성자 자체만으로 반환될 객체의 특성을 제대로 표현하지 못하지만 정적 팩터리는 이름만 잘 지으면 반환될 객체의 특성을 쉽게 묘사할 수 있다.

BigInteger(int, int ,Random) //생성자
BigInteger.probablePrime //정적 팩터리 메서드 

2. 호출될 때마다 인스턴스를 새로 생성하지 않아도 된다
불변 클래스는 인스턴스를 미리 만들어 놓거나 새로 생성한 인스턴스를 캐싱하여 재활용하는 식으로 불필요한 객체 생성을 피할 수 있다. 예를 들어 Boolean.valueOf(boolean) 메서드는 객체를 아예 생성하지 않는다. 따라서 같은 객체가 자주 요처오디는 상황에 성능을 끌어올려 줄 수 있다.

3. 반환 타입의 하위 타입 객체를 반환할 수 있는 능력이 있다.
인터페이스 자체를 반환하여, 구현 클래스를 공개하지 않고도 그 객체를 반환할 수 있다. 구현 클래스의 상세를 숨길 수 있고, 사용자는 객체를 인터페이스만으로 다룰 수 있다.

4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.
예를 들어, EnumSet 클래스는 원소의 수에 따라 두 가지 하위 클래스 중 하나의 인스턴스를 반환한다.

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

public class TicketStore {
  /** TicketSeller는 인터페이스이고 구현체가 없음에도 아래와 같은 메서드 작성이 가능하다.**/
    public static List<TicketSeller> getSellers(){
        return new ArrayList<>();
    }
}

참고자료


단점은 다음과 같다.

1. 상속을 하려면 public 이나 protected 생성자가 필요하니 정적 팩터리 메서드만 제공하면 하위 클래스를 만들 수 없다.

2. 정적 팩터리 메서드는 프로그래머가 찾기 어렵다.

따라서 흔히 사용하는 명명 방식이 존재한다.

  • from: 매개변수를 하나 받아서 해당 타입의 인스턴스를 반환하는 형변환 메서드

    Date d = Date.from(instant);
  • of: 여러 매개변수를 받아 적합한 타입의 인스턴스를 반환하는 집계 메서드

    Set<Rank> faceCards = EnumSet.of(JACK, QUEEN, KING);
  • valueOf: from과 of의 더 자세한 버전

    BigInteger prime = BigInteger.valueIf(Integer.MAX_VALUE);
  • instance 혹은 getInstance: 매개변수로 명시한 인스턴스를 반환, 같은 인스턴스임을 보장하진 않는다.

    StackWalker luke = StackWalker.getInstance(options);
  • create 혹은 newInstance: instance 혹은 getInstance와 같지만, 매번 새로운 인스턴스 생성을 보장

    Object newArray = Array.newInstance(classObject, arrayLen);
  • getType: getInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 사용

    FileStore fs = Files.getFileStore(path);
  • newType: newInstance와 같으나, 생성할 클래스가 아닌 다른 클래스에 팩터리 메서드를 정의할 때 사용

    BufferedReader br = Files.newBufferedReader(path);
  • type: getType과 newType의 간결한 버전

    List<Complaint> litany = Collections.list(legacyLitany);
profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️

0개의 댓글