생성자 말고 정적 팩토리 메서드

June·2022년 2월 17일
0

우테코

목록 보기
8/84
    @Test
    public void isZeroWhenStarted() {
        Location location = new Location();
        ...
    }

이펙티브 자바 아이템 1를 참고해보면 좋을 거 같아요 :)

생성자 대신 정적 팩토리 메서드

여기서 말하는 디자인 패턴의 팩토리 메서드와 다른 것이다. public을 이용한 생성자 대신 static 팩토리 메서드를 제공하는 것이다.

정적 팩토리 메서드란 객체 생성의 역할을 하는 클래스 메서드다.

java.time.LocalTime

// LocalTime.class
...
public static LocalTime of(int hour, int minute) {
  ChronoField.HOUR_OF_DAY.checkValidValue((long)hour);
  if (minute == 0) {
    return HOURS[hour];
  } else {
    ChronoField.MINUTE_OF_HOUR.checkValidValue((long)minute);
    return new LocalTime(hour, minute, 0, 0);
  }
}
...

// hour, minutes을 인자로 받아서 9시 30분을 의미하는 LocalTime 객체를 반환한다.
LocalTime openTime = LocalTime.of(9, 30); 

실제 java.time 패키지에 포함된 LocalTime 클래스의 코드다.

메서드명이 of이며 생성자를 통해서 객체를 생성하는 것이 아닌 메서드를 통해서 객체를 생성하고 있다.

그렇다면 어떤 장점이 있길래 있는 생성자를 놔두고 이런걸 쓰는가?

이펙티브 자바에서는 처음으로 소개하는 아이템이 바로 이 정적 팩토리 메서드라고 한다.

장점

1. 이름을 가질 수 있다.

    public static Position createStartPosition() {
        return new Position(START_POSITION_VALUE);
    }

나는 코드 리뷰를 받고 메서드를 이렇게 변경해보았다.

Position position = Position.createStartPosition();

이렇게 메서드 명을 통해 더욱 명시적으로 무엇이 생성되었는지 드러난다.

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

만약 자주 사용되는 것이라면 static으로 만들고 캐싱하게 할 수도 있다.
또한 생성자를 private으로 설정해서 객체 생성 방법을 제한할 수 있다.

3. 하위 자료형 객체를 반환할 수 있다.

하위 자료형 객체를 반환하는 정적 팩토리 메서드의 특징은 상속을 사용할 때 확인할 수 있다. 이는 생성자의 역할을 하는 정적 팩토리 메서드가 반환값을 가지고 있기 때문에 가능한 특징이다.

Basic, Intermediate, Advanced 클래스가 Level라는 상위 타입을 상속받고 있는 구조를 생각해보자. 시험 점수에 따라 결정되는하위 등급 타입을 반환하는 정적 팩토리 메서드를 만들면, 다음과 같이 분기처리를 통해 하위 타입의 객체를 반환할 수 있다.

public class Level {
  ... 
  public static Level of(int score) {
    if (score < 50) {
      return new Basic();
    } else if (score < 80) {
      return new Intermediate();
    } else {
      return new Advanced();
    }
  }
  ...
}

4. 객체 생성을 캡슐화할 수 있다.

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

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

public class CarDto {
  private String name;
  private int position;
  
  pulbic static CarDto from(Car car) {
    return new CarDto(car.getName(), car.getPosition());
  }
}


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

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

Car carDto = CarDto.from(car); // 정적 팩토리 메서드를 쓴 경우
CarDto carDto = new CarDto(car.getName(), car.getPosition); // 생성자를 쓴 경우

정적 팩토리 메서드 네이밍 컨벤션

  • from : 하나의 매개 변수를 받아서 객체를 생성
  • of : 여러개의 매개 변수를 받아서 객체를 생성
  • getInstance | instance : 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있음.
  • newInstance | create : 새로운 인스턴스를 생성
  • get[OtherType] : 다른 타입의 인스턴스를 생성. 이전에 반환했던 것과 같을 수 있음.
  • new[OtherType] : 다른 타입의 새로운 인스턴스를 생성.

https://velog.io/@ljinsk3/%EC%A0%95%EC%A0%81-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C%EB%8A%94-%EC%99%9C-%EC%82%AC%EC%9A%A9%ED%95%A0%EA%B9%8C

0개의 댓글