[Effective java] 정적 팩토리 메소드 (Static factory method)
정적 팩토리 메소드 (Static factory method) 란?
객체를 생성하는 기법중의 하나. 객체를 생성하는 public static method 를 선언한 것이다.
ex) java.lang.Boolean
클래스의 valueOf()
메소드
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
장점
-
정적 팩터리 메서드에는 이름이 있다.
ex)
java.math.BigInteger
클래스의probableInteger()
메소드public static BigInteger probablePrime(int bitLength, Random rnd) { if (bitLength < 2) throw new ArithmeticException("bitLength < 2"); return (bitLength < SMALL_PRIME_THRESHOLD ? smallPrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd) : largePrime(bitLength, DEFAULT_PRIME_CERTAINTY, rnd)); }
-
호출할 때마다 새로운 객체를 생성할 필요가 없다.
ex) 상기의
Booelan.valueOf()
메소드 -
반환값 자료형의 하위 자료형 객체를 반환할 수 있다.
ex1)
java.util.EnumSet
클래스noneOf()
메소드.EnumSet
클래스를 상속받은RegularEnumSet
클래스와JumboEnumSet
클래스 중 조건에 따라 다른 클래스를 반환한다.class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> { ... }
class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> { ... }
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); }
ex2) 서비스 제공자 프레임워크 (Service Provider Framework - JDBC 등) 의 근간이 됨.서비스 제공자 프레임워크의 구조
1) 서비스 인터페이스
public class Service { // 서비스 고유의 메소드들이 이 자리에 온다. }
2) 제공자 등록 API
3) 서비스 접근 API
// 서비스 등록과 접근에 사용되는 객체 생성 불가능 클래스 public class Services { // 객체 생성 방지 private Services() {}; // 서비스 이름과 서비스 간 대응관계 보관 private static final Map<String, Provider> providers = new ConcurrentHashMap<>(); public static final String DEFAULT_PROVIDER_NAME = "<def>"; //제공자 등록 API public static void registerDefaultProvider(Provider p) { registerProvider(DEFAULT_PROVIDER_NAME, p); } public static void registerProvider(String name, Provider p) { providers.put(name, p); } // 서비스 접근 API public static Service newInstance() { return newInstance(DEFAULT_PROVIDER_NAME); } public static Service newInstance(String name) { Provider p = providers.get(name); if (p == null) { throw new IllegalArgumentException("No provider registered with name: " + name); } return p.newService(); } }
4) 서비스 제공자 인터페이스
public interface Provider { Service newService(); }
-
형인자 자료형(parameterized type) 객체를 만들기가 수월하다.(단, 자바 1.7 부터 생성자를 호출할 때도 자료형 유추를 사용할 수 있도록 update 되었다. 아래와 같이 다이아몬드 연산자가 추가됨으로써 표준 컬렉션 메서드에서 정적 팩터리 메서드를 추가할 필요가 없어졌다.)
Map<String, List<String>> myMap = new HashMap<>();
문제점
-
public 이나 protected 로 선언된 생성자가 없으면 하위 클래스를 만들 수 없다.
-
다른 정적 메서드와 확연히 구분되지 않는다.