정적 팩토리 메서드와 빌더 패턴

정적 팩토리 메서드

조슈아 블로크의 저서 “이펙티브 자바”에서는 생성자 대신 정적 팩토리 메서드를 고려하라!라고 한다.
생성자와 정적 팩토리 메서드는 객체를 생성한다는 같은 역할을 하고 있지만 그 활용도는 엄연히 차이가 난다

 어플리케이션을 개발하다보면 계층 간에 데이터를 전송하기 위한 객체로 DTO(Data transfer object) 정의해서 사용한다.

public class CarDto {
  private String name;
  private int position;

  pulbic static CarDto from(Car car) {
    return new CarDto(car.getName(), car.getPosition());
  }
}

DTO와 Entity간에는 자유롭게  변환이 가능해야 하는데, 
정적 팩터리 메서드를 사용하면 내부 구현을 모르더라도 쉽게 변환할  있다.

// Car -> CatDto 로 변환
CarDto carDto = CarDto.from(car);


만약, 정적 팩토리 메서드를 쓰지 않고 DTO로 변환한다면 
외부에서 생성자의 내부 구현을 모두 드러내야 한다.

Car carDto = CarDto.from(car); // 정적 팩토리 메서드를 쓴 경우

CarDto carDto = new CarDto(car.getName(), car.getPosition); // 생성자를 쓴 경우

빌더 패턴과 정적 팩토리 메서드


** 정적 팩토리 메서드 사용이 좋은 경우

매개변수가 적을  (2~3 이하)
객체 생성 로직이 복잡하거나 캐싱이 필요할 
상황에 따라 다른 객체를 반환해야  

** 빌더 패턴 사용이 좋은 경우

매개변수가 많을  (4 이상)
선택적 매개변수가 많을 
불변 객체를 생성해야  
객체 생성에 여러 단계가 필요할 

[정리]
DTO나 간단한 객체는 정적 팩토리 메서드
도메인 객체나 복잡한 객체는 빌더 패턴를 사용하자.

일반적인 정적 팩토리 메서드 명명 규칙


public class Order {
    // from: 다른 객체로부터 인스턴스 생성
    public static Order from(OrderRequest request) {
        return new Order(request.getCustomerId(), request.getItems());
    }

    // of: 여러 매개변수로부터 인스턴스 생성
    public static Order of(String customerId, List<OrderItem> items) {
        return new Order(customerId, items);
    }

    // create: 새로운 인스턴스 생성
    public static Order createEmpty() {
        return new Order(null, new ArrayList<>());
    }

    // valueOf: 상세한 버전
    public static Order valueOf(Map<String, Object> orderMap) {
        return new Order(
                (String) orderMap.get("customerId"),
                (List<OrderItem>) orderMap.get("items")
        );
    }
}