본문 바로가기
Study/Java

[Java] 정적 팩토리 메서드 장단점과 사용시기

by 검프 2021. 3. 10.

정적 팩토리 메소드의 특징

정적 팩토리 메소드의 장점은 곧 특징이 돼요. 크게 4가지의 장점이 있어요.

장점

이름이 있으므로 생성자에 비해 가독성이 좋다.

호출할 때마다 새로운 객체를 생성할 필요가 없다.

하위 자료형 객체를 반환할 수 있다.

형인자 자료형 객체를 만들 때 편리하다.

단점으로는 2가지가 있는데요.

단점

정적 팩토리 메서드만 있는 클래스라면, 생성자가 없으므로 하위 클래스를 못 만든다.

정적 팩토리 메서드는 다른 정적 메서드와 잘 구분되지 않는다. (문서만으로 확인하기 어려울 수 있음)

장, 단점을 알면, 이제 도대체 언제 써야하는지 알아야겠죠? 그전에 매번 헷갈리는 정적 팩토리 메소드의 네이밍 컨벤션을 조금 살펴보고 가야할거 같아요.

정적 팩토리 메소드 네이밍 컨벤션

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

      Number number =  Number.from(instant);
  • of: 여러개의 매개변수를 받아 적합한 타입의 인스턴스를 반환

    이번 미션 코드에서 사용한다면,

      package java.util;
    
      public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E> implements Cloneable, Serializable {
      ...
      public static <E extends Enum<E>> EnumSet<E> of(E var0, E var1, E var2) {
              EnumSet var3 = noneOf(var0.getDeclaringClass());
              var3.add(var0);
              var3.add(var1);
              var3.add(var2);
              return var3;
          }
      ...
      }
    
      public enum Number {
      ...
          ACE("A", 11, 1),
          TWO("2", 2),
          THREE("3", 3),
      ...
      }
    
      public static void main(String[] args) {
          EnumSet<Number> numberSet = EnumSet.of(Number.ACE, Number.TWO, Number.THREE);
      }
  • valueOf: from과 of의 조금더 자세한 버전

      package java.math;
      public class BigDecimal extends Number implements Comparable<BigDecimal> {
      ...
      public static BigDecimal valueOf(long val) {
              if (val >= 0 && val < zeroThroughTen.length)
                  return zeroThroughTen[(int)val];
              else if (val != INFLATED)
                  return new BigDecimal(null, val, 0, 0);
              return new BigDecimal(INFLATED_BIGINT, val, 0, 0);
      }
      ...
      }
    
      public static void main(String[] args) {
          BigDecimal lucky = BigDeciaml.valueOf(777);
      }
  • instance, getInstance: (매개변수를 받는다면) 매개변수로 명시한 인스턴스를 반환하지만, 같은(equals) 인스턴스임을 보장하지 않음. 즉 , 매개변수와 같은 값을 갖지 않을 수도 있다.

      package java.util;
    
      public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
      ...
      public static Calendar getInstance(TimeZone zone)
          {
              return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
          }
      ...
      }
    
      public static void main(String[] args) {
              Calendar instance = Calendar.getInstance(Locale.KOREA);
      }
  • create or newInstance: getInstance와 같지만 호출 시 매번 다른 객체를 반환한다.

  • getXxxx: getInstance와 같으나 호출하는 클래스와 다른 타입의 인스턴스를 반환할때 사용

    • 예를들어 Date.getInstance() 는 Date 타입의 인스턴스를 반환하지만 Date와 상관없는 Period 타입을 반환한다면 Date.getPeriod() 가 된다.
  • newXxxx: getXxxx와 같으나 매번 새로운 인스턴스를 반환한다. newInstance와 같지만 반환될 객체의 클래스와 다른 클래스에 팩토리 메소드가 있을 때 사용한다. Type은 팩토리 메소드가 반환할 객체의 자료형.

내가 생각하는 사용시기

주 생성자, 부생성자로도 충분하다.

다만 생성의 의미를 더 정확하게 할 수 있다면 정적 팩토리 메소드를 써도 괜찮을듯..!

private static final Map<Integer, LottoBall> lottoBalls = new HashMap<>();

    static {
        for (int i = MIN_LOTTO_VALUE; i <= MAX_LOTTO_VALUE; i++) {
            lottoBalls.put(i, new LottoBall(i));
        }
    }

    private final int value;

    private LottoBall(final int value) {
        this.value = value;
    }

    public static LottoBall from(final int value) {
        if (Objects.isNull(lottoBalls.get(value))) {
            throw new IllegalArgumentException(String.format(PERMIT_LOTTO_NUMBER_EXCEPTION_MESSAGE, MIN_LOTTO_VALUE, MAX_LOTTO_VALUE));
        }
        return lottoBalls.get(value);
    }

댓글