반응형
객체를 만드는 방법인 생성자(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의 객체를 생성할 경우 사용한다. 일반적으로 항상 새로운 객체를 만들어 반환한다.
반응형
'Java > [책] 이펙티브 자바' 카테고리의 다른 글
[이펙티브 자바] 규칙6. 메모리 누수 (leak) (0) | 2021.11.14 |
---|---|
[이펙티브 자바] 규칙5. 불필요하게 객체를 여러번 만들지 않기 (String, Calendar 등) (0) | 2021.11.06 |
[이펙티브 자바] 규칙4. Util 클래스와 같이 객체 생성이 필요없는 클래스는 private 생성자를 사용 (0) | 2021.10.24 |
[이펙티브 자바] 규칙3. 싱글턴 패턴 (0) | 2021.10.20 |
[이펙티브 자바] 규칙2. 생성자 인자가 많을 때는 Builder 패턴 (0) | 2021.10.10 |