Java

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

quedevel 2022. 5. 24. 10:18
728x90
반응형

클라이언트가 클래스의 인스턴스를 얻는 전통적인 수단은 public 생성자다.

하지만 모든 프로그래머가 꼭 알아둬야 할 기법이 하나 더 있다.

클래스는 생성자와 별도로 정적 팩터리 메서드를 제공할 수 있다.

✅ 정적 팩터리 메서드는 디자인 패턴에서의 팩터리 메서드와 다르다.


👍 장점

1️⃣ 이름을 가질 수 있다.

class Member {
    private String mbrId;
    private String mbrPw;

    public static Member ofMemberIdAndMbrPw(String mbrId, String mbrPw) {
        Member member = new Member();
        member.setMbrId(mbrId);
        member.setMbrPw(mbrPw);
        return member;
    }
}
  • 객체의 특성을 쉽게 묘사할 수 있다.

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

public static Boolean valueOf(boolean bololean){
  return b Boolean.TRUE : Boolean.FALSE;
}
  • 인스턴스를 미리 만들어 놓거나 새로 생성한 인스턴스를 캐싱하여 재활용하는식으로 불필요한 객체 생성을 피할 수 있다.

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

  • 반환할 객체의 클래스를 자유롭게 선택할 수 있게하는 엄청난 유연성을 제공한다.
  • 반환하는 타입을 인터페이스 타입으로 할 경우, 해당 인터페이스를 구현하는
    다른 타입의 객체들을 반환할 수 있음을 말한다. (상속)
  • 정적 팩터리를 사용하는 클라이언트는 얻은 객체를 인터페이스만으로 다루게 된다.

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

/**
 * Creates an empty enum set with the specified element type.
 *
 * @param <E> The class of the elements in the set
 * @param elementType the class object of the element type for this enum
 *     set
 * @return An empty enum set of the specified type.
 * @throws NullPointerException if {@code elementType} is null
 */
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
    Enum<?>[] universe = getUniverse(elementType);
    if (universe == null)
        throw new ClassCastException(elementType + " not an enum");

    if (universe.length <= 64)
        return new RegularEnumSet<>(elementType, universe);
    else
        return new JumboEnumSet<>(elementType, universe);
}
  • 예시로 EnumSet 클래스는 publi 생성자 없이 오직 정적 팩터리 메서드만 제공한다.
  • 만약 원소가 64개 이하이면 원소들은 long 변수 하나로 관리하는 RegularEnumSet의 인스턴스
  • 65개 이상이면 long 배열로 관리하는 JunboEnumSet의 인스턴스를 반환한다.
  • 클라이언트는 이 두 클래스의 존재를 몰라도 된다.

public abstract class Discount {
  public static <E extends Discount> Discount getInstance(String code){
    return code.equals("1")? new RateDiscount() : new FixedDiscount();
  }
}
public class FixedDiscount extends Discount{
  public FixedDiscount() {
    System.out.println("FixedDiscount.FixedDiscount");
  }
}
public class RateDiscount extends Discount{
  public RateDiscount() {
    System.out.println("RateDiscount.RateDiscount");
  }
}

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

👎 단점

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

  • 컬렉션 프레임워크의 유틸리티 구현 클래스들은 상속할 수 없다

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

  • 생성자처럼 API 설명에 명확히 드러나지 않으니 샂용자는 정적 팩터리 메서드 방식 클래스를 인스턴화할 방법을 알아내야 한다.

참고 자료

Joshua Bloch, 『Effective Java 3/E』, 개앞맵시 옮김, 프로그래밍인사이트(2018)
http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788966262281&orderClick=LEa&Kc=

728x90
반응형