개발/Java

정적 팩토리 메서드 Static Factory Method

선우. 2024. 4. 11. 10:28

What

정적 팩토리 메서드란?

  • 클래스의 인스턴스를 반환하는 단순한 정적 메서드다.
  • 클래스는 클라이언트에 public 생성자 외에도 정적 팩토리 메서드를 제공할 수 있다.
  • 팩토리 메서드 디자인 패턴과는 전혀 관련 없는 개념이니 혼동하지 않도록 주의하자.

 

Why

장점 - 왜 사용하는가?

1. 이름을 가질 수 있다.

Human(String name, int height)
Human(String name, int weight) // 불가능, 위와 동일한 생성자 시그니처
Human(int weight, String name) // 가능, but 의미를 알 수 없음
  • 동일한 시그니처로는 생성자를 단 하나만 만들 수 있다.
  • 순서를 변경해 다른 시그니처로 만들 수 있지만, 개발자는 앞에오는 int 매개변수가 height인지 weight인지 기억할 수 없을 것이다. 설명 문서를 찾아보지 않고는 생성자의 의미를 알 수 없게 된다.
public static Human withHeight(String name, int height) {
		Human human = new Human(name);
		human.height = height;
		return human;
}
public static Human withWeight(String name, int weight) {
		Human human = new Human(name);
		human.weight = weight;
		return human;
}
  • 반면 정적 팩토리 메서드는 매개변수의 순서와 타입이 같더라도 메서드 명을 다르게 정의할 수 있기 때문에 위와 같은 걱정을 할 필요가 사라진다.
  • 또한 객체 생성의 의미가 분명하게 드러난다.

 

2. 인스턴스를 새로 생성하지 않아도 된다. (연관: Fly-weight 패턴)

public class OrderStatus {

    private static final Map<String, OrderStatus> orderStatusMap = new HashMap<>();
    private static final List<String> status = List.of("주문 접수", "조리 중", "배달 중", "배달 완료");

    static {
        status.forEach(s -> orderStatusMap.put(s, new OrderStatus(s)));
    }

    private String statusValue;

    private OrderStatus() {}
    
    private OrderStatus(String statusValue) {
        this.statusValue = statusValue;
    }

    public static OrderStatus getInstance(String status) {
        return orderStatusMap.get(status);
    }
}
  • 인스턴스를 미리 만들어 놓거나 새로 생성한 인스턴스를 캐싱해 재활용하는 방식으로 불필요한 객체 생성 비용을 줄일 수 있다.
  • 싱글톤 객체로 만들거나, 인스턴스화가 불가능하게 막을 수 있다.

 

OrderStatus os1 = OrderStatus.getInstance("주문 접수");
OrderStatus os2 = OrderStatus.getInstance("주문 접수");

System.out.println(os1);
System.out.println(os2);
OrderStatus@3f0ee7cb
OrderStatus@3f0ee7cb
  • 동치(== 연산이 true)인 인스턴스가 단 하나뿐임을 보장할 수 있다.

 

3. 반환 타입의 하위 타입 객체를 반환할 수 있다.

 

4. 입력 매개변수에 따라 매번 다른 클래스의 객체를 반환할 수 있다.

 

5. 정적 팩토리 메서드를 작성하는 시점에는 반환할 객체의 클래스가 존재하지 않아도 된다.

 

단점 - 왜 사용하기 불편한가?

1. 정적 팩토리 메서드만 제공하면 상속이 불가능하다.

  • 정적 팩토리 메서드만 제공한다는 것은 생성자를 private으로 제공한다는 의미이다.
  • 상속은 내부적으로 부모 클래스의 기본 생성자를 호출하는데, 접근이 불가능하므로 상속도 불가능하다.

 

2. 개발자가 정적 팩토리 메서드를 찾기 어려울 수 있다.

  • 생성자의 경우 일반 메서드와 확실하게 구분이 가능하지만, 정적 팩토리 메서드의 경우 구분이 어려울 수 있다.
  • 이럴 경우, 객체를 생성/반환할 때 정적 팩토리 메서드를 사용하도록 주석을 달거나 문서화를 제대로 해야 한다.

 

How

어떻게 사용하는가?

  • 네이밍 컨벤션을 지켜 사용하자.
    • from : 하나의 매개변수를 받아서 객체를 생성한다.
    • of : 여러개의 매개변수를 받아서 객체를 생성한다.
    • getInstance / instance : 인스턴스를 생성한다. 이전에 생성해둔 인스턴스를 반환할 수 있다.
    • newInstance / create : 새로운 인스턴스를 생성한다.
    • get[OtherType] : 다른 타입의 인스턴스를 생성한다. 이전에 생성해둔 인스턴스를 반환할 수 있다.
    • new[OtherType] : 다른 타입의 새로운 인스턴스를 생성한다.
  • public 생성자와 정적 팩토리 메서드 각자의 쓰임새에 따라 상대적 장단점을 이해하고 사용하자.

 

Reference