반응형

객체를 만드는 방법인 생성자(Constructor) 대신 객체를 리턴하도록 하는 public으로 선언된 메서드인 정적 팩터리 메서드를 사용하는 것이 좋은 점이 많다.

 

정적 팩터리 메서드는 다양한 클래스에서 볼 수 있는데, String 클래스의 valueOf 메서드가 그중 하나이다.

    public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

    
    public static String valueOf(char data[]) {
        return new String(data);
    }

 

장점

1. 이름이 있다.

  • 생성자는 이름이 없어 오직 메소드 인자의 시그니처를 보고 파악해야 한다.
  • 정적 팩터리 메서드는 메서드 이름으로 어떤 의미의 객체를 리턴하는지 쉽게 파악할 수 있다.

 

2. 생성자처럼 반드시 새로운 객체를 만들도록 하지 않을 수 있다.

  • 내가 생각하는 가장 큰 장점 중에 하나로, 반드시 새로운 객체를 생성하지 않고, 이미 만들어져 있는 객체를 제공할 수도 있다.
  • 동일한 객체 생성을 요청하는 경우, 이미 만들어 놓은 객체 변수를 리턴할 수 도 있으며 또는 캐시를 사용하여 제공할 수 도 있다.
  • 객체 생성하는데 비용이 클 경우, Immutable 클래스인 경우 사용하기에 좋을 것이다.
    // Boolean code
        public static final Boolean TRUE = new Boolean(true);
        public static final Boolean FALSE = new Boolean(false);
    
        public static Boolean valueOf(boolean b){
            return b ? TRUE : FALSE;
        }

 

3. 생성자처럼 반드시 해당 클래스의 객체를 생성하지 않고, 하위 계층의 클래스를 생성할 수 있다.

  • 생성자는 반드시 자신의 객체만을 리턴한다.
  • 정적 팩터리 메서드는 반환형에 하위 계층 또는 구현체를 리턴할 수 있으므로 더욱 유연하다.
  • java.util.Collections는 다양한 정적 팩터리 메서드가 존재하는데 아래 예제에서는 리턴하는 객체가 Collections에서만 호출 가능한 inner class인 SynchronizedCollection를 생성하여 리턴한다. 이처럼 외부에서는 객체 생성 불가능한 클래스도 정적 메서드 클래스를 통해 리턴할 수 제공할 수 있다.
    package java.util;
    ...
    
    public class Collections {
        ...
    
        public static <T> Collection<T> synchronizedCollection(Collection<T> c) {
            return new SynchronizedCollection<>(c);
        }
    
    
        static class SynchronizedCollection<E> implements Collection<E>, Serializable {
            private static final long serialVersionUID = 3053995032091335093L;
    
            final Collection<E> c;  // Backing Collection
            final Object mutex;     // Object on which to synchronize
    
            SynchronizedCollection(Collection<E> c) {
                this.c = Objects.requireNonNull(c);
                mutex = this;
            }
            
            ...
        }
        
        
        ...
        
    }

 

4. 제네릭을 사용한 객체를 만들 때 편리하다. (JDK  1.7부터는 생성자에서도 지원한다.)

 

단점

1. 정적 팩터리 메서드만 제공하는 클래스라면, 즉 생성자가 private로 되어 있어 생성자를 이용하여 객체를 생성할 수 없다면, 하위 클래스를 만들 수 없다.

 

2. 정적 팩터리 메서드는 일반 메서드와 다른 점이 없으므로 해당 메서드가 정적 팩터리 메서드인지 바로 알 수는 없다. 따라서 문서를 읽어야지 파악 가능하다.

 

 

2번 단점으로 인해, 일반적으로 정적 팩터리 메서드의 네이밍은 아래와 같이 작성한다.

  • valueOf : 주어진 값과 같은 값을 갖는 객체를 반환한다.
        // String.valueOf
        public static String valueOf(Object obj) {
            return (obj == null) ? "null" : obj.toString();
        }​
  • of : valueOf와 동일
        // Optional.of
        public static <T> Optional<T> of(T value) {
            return new Optional<>(value);
        }​
  • getInstance : 일반적으로 이미 존재하는 객체를 반환한다.
    // Singleton example
    public class ExampleClass {
        private static ExampleClass instance = new ExampleClass();
        private ExampleClass() {}
        public static ExampleClass getInstance() {
            return instance;
        }
    }​
  • newInstance : 일반적으로 항상 새로운 객체를 만들어 반환한다.
    // Class.newInstance
    clazz.newInstance()​
  • getType : 특정 클래스에서 Type의 객체를 생성할 경우 사용한다. 일반적으로 이미 존재하는 객체를 반환한다.
  • newType : 특정 클래스에서 Type의 객체를 생성할 경우 사용한다. 일반적으로 항상 새로운 객체를 만들어 반환한다.

 

반응형

+ Recent posts