해당 포스트는 "Effective Java" 책의 내용을 요약한 것이다.



※ 정적 팩터리 메서드

다음 코드는 기본 타입 boolean을 통해 Boolean 객체를 생성하는 정적 팩터리 메서드 예이다. 

public static Boolean valueOf(boolean b){
  return b ? Boolean.TRUE : Boolean.FALSE;
}

참고로 정적 팩터리 메서드는 팩터리 메서드 패턴이란 완전 다르다.


public 생성자 대신 정적 팩터리 메서드를 사용할 때의 장/단점을 살펴보자.


- 정적 팩터리 메서드 장점

1. 생성자와 달리 정적 팩터리 메서드는 이름을 가진다. 

: 일반 생성자는 단지 "클래스 이름()" 형식을 사용한다. 따라서 생성자 매개변수에 따라 조금씩 달라지는 클래스가 있다면 정적 팩터리 메서드에서 그에 맞는 이름을 지어 줄시 가독성이 더 향상된다. 클래스는 시그너처(signature)별로 하나의 생성자만 넣을 수 있다. 만약 동일한 시그너처를 가진 생성자가 두 개 이상 필요하다면 매개변수를 순서를 바꿔서 생성자를 만들어야 한다. 그러면 사용자가 코딩하는 데 엉뚱한 생성자를 사용할 수 있다. 하지만, 정적 팩토리 메서드를 사용하면 이름이 있으므로 그런 문제를 가지지 않는다.


2. 생성자와는 달리 호출할 때마다 새로운 객체를 생성할 필요가 없다.

: 변경 불가능한 클래스나 만든 객체를 재사용하는 캐시를 사용할 때 정적 팩터리 메서드를 사용하면 같은 객체가 불필요하게 생성되는 일을 피할 수 있다. 첫 번째 valueOf 예제가 이 장점을 잘 활용한 예이다. 또한 플라이웨이트 패턴과 같이 동일한 객체가 요청되는 일이 잦고, 특히 객체를 만드는 비용이 클 때 적용하면 성능을 크게 개선할 수 있다. 플라이웨이트 패턴에 대해서 알고 싶다면 해당 문장을 클릭해라.


3. 생성자와 달리 반환값 자료형의 하위 자료형 객체를 반환할 수 있다. 

: 반환되는 객체의 클래스를 훨씬 유연하게 동적으로 결정할 수 있다. public 으로 선언되지 않은 클래스의 반환도 가능하다. 자바 EnumSet의 경우 public 생성자가 없고 정적 팩터리 메서드만 있다. 해당 팩터리 메서드는 enum의 개수에 따라 동적으로 다른 하위 자료형 객체를 반환한다. 이렇게 구현하면 반환된 객체의 실제 구현 세부사항이 아니라 상위 클래스/인터페이스만 보고 코드를 작성하게 할 수 있어 바람직하다.


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

Map<String, List<Sting>> m = new HashMap<String, List<String>>();

위와 같은 코드는 형인자를 두 번 사용한다. 이처럼 하게 되면 나중에 형인자가 복잡해지고 코드가 길어질 가능성이 높다. 하지만, 정적 팩터리 메서드를 사용하면 컴파일러가 형인자를 스스로 알아내도록 할 수 있다.

public static <K,V> MashMap<K,V> newInstance(){ return new HashMap<K, V>(); }

Map<String, List<String>> m = HashMap.newInstance();

위와 같이 정적 팩터리 메서드를 사용하면 간결하게 객체를 생성할 수 있다.


- 정적 팩터리 메서드 단점

1. 가장 큰 문제는 public이나 protected로 선언한 생성자가 없어서 하위 클래스를 만들 수 없다. 대안으로 상속 대신 구성(composition) 기법을 사용해야 한다.

2. 정적 팩터리 메서드가 확연히 구분되지 않는다. 생성자는 다른 메서드와 확실하게 구분되지만 정적 팩터리 메서드는 구분이 힘들고 사용법도 파악하기가 힘들다. 따라서 이름을 지을 시 신중하게 해야한다.

*정적 팩터리 메서드가 효과적인 경우가 꽤 많다. 따라서 무조건 public 생성자를 사용하려고 하지 말고 정적 팩터리 메서드의 사용을 고려해 보는 게 좋다.


+ Recent posts