📜 제목으로 보기

생성자 규칙

나만의 규칙

  • 생성 루트가 여러개 ex> List<String> or List<Car>인 일급컬렉션
    1. private 필요속성(만) 받는 기본생성자
    2. public fromStrings( List< String > )
      • inputView에서 검증을 하고 오므로 검증없이 -> List<객체>로 변환 -> 생성자
    3. public from객체(List< 객체 >)
      • test등에서 단일객체 -> List add되어 들어오는데, 복수 검증(중복)을 추가후 -> 생성자
  • VO, 단일객체라도 숫자형이라면 -> inputView에서 형변환후, 해당형으로 검증되도록
    1. inputView에서 따로 검증안한다면, public 생성자에서 검증까지 다 처리하면 될 듯함.
      • inputView에서는 VO는 형변환하고나서 -> 검증하자.
    2. inputView 검증해야하는 상황이라면? -> 형변환후 int만 검증
      1. public 기본생성자(원본 타입) with 노검증(for inputView거친 뒤 controller or 숫자VO 연산)
      2. public fromNumber(원본타입) with 검증(for 테스트 or int직접생성)

일급컬렉션 생성자와 사용이유

생성자 2+1개

fromXXXX: InputView에서 검증된 List< String >를 받는 public 정적팩토리메서드
  • InputView.getXXX() 에서 검증 후 들어오는 ** -> **List< String >으로 들어올 것이기 때문에 .fromStrings( )형식으로 작성한다.

    • String List -> 단일객체 List로 변환되어 -> 기본 생성자를 부른다.
      public static Cars fromNames(List<String> values) {
          //input에서 검증하고 와서, 변환만
          List<Car> cars = values.stream()
              .map(value -> Car.from(value))
              .collect(Collectors.toList());
          return new Cars(cars);
      }
    
from: 테스트 등에서 List< 단일객체 >를 받는 public 정적팩토리메서드
  • 기본생성자는 private하게 유지하기 위해, 테스트용 public 기본 생성자 from ( List< 단일객체 >로 생각하자.

    • 따로 개별 검증은 필요 없고(단일객체 생성시 이미 검증) -> 중복검사 등만 필요
      public static Cars from(List<Car> cars) {
          //중복 검증 등
          return new Cars(cars);
      }
    
기본생성자: private + List< 단일객체 >
  • inputView 검증-> fromStrings

  • test -> from -> 복수검증

  • 기본생성자는 일단 검증 없이 생성만 하는 역할을 하게 한다.

      private Cars(List<Car> cars) {
          this.cars = cars;
      }
    

쓰는 이유 4가지

01 검증 통과해야만 생성 가능한 자료구조(비지니스 종속 자료구조)
  • 흩어져있는 검증 기능들을 외울 수 없다. 신입사원이 와도 바로 작동하도록 하는 객체를 만들어야한다.

  • 해당, util등에서 처리할게 아니라 검증 만족시 생성가능한 자료구조를 만들어 신입사원도 쓸 수 있게 해야한다.

      public static Cars from(List<Car> cars) {
          Validator.validateCarsName(getCarNames(cars));
          return new Cars(cars);
      }
    
02 setter/add 등이 없는 불변구조
  • List는 add, map은 put 등의 메서드를 제공하는데

    • 일급컬렉션으로 감싸서 생성자와 getter류 기능만 제공하도록하고 setter 등을 제공하지 않음녀 불변구조가 된다.

    • 자료구조에 final을 붙혀도 해당 context에서 재할당만 불가 -> add, put 등은 가능함.

      • cf) 일급컬렉션에 변수는 1개이며, final이 붙어서 최초생성이후 변경할 수 없게 한다.
        private final List<Car> cars;
      
03 상태(변수)와 행위(기능)을 자료구조와 함께 한 class에 다 모으기(냉무)
05 이름을 가지는 자료구조가 됨.(냉무)

일급컬렉션 테스트

단일객체 -> 일급컬렉션 순서대로 생성

  • 단일객체 -> 일급컬렉션 순서대로 생성하도록 전역변수 -> @BeforeEach에서
    • List< Car >를 받으면서 중복 등 다수검증하는 from으로 생성한다.
    • 단일 객체생성은 여기서는 다루지 않지만, 검증이 들어간 로직으로 해야할 듯.
//1. 일급컬렉 Test: @BeforeEach에서 단일객체 개별생성 후(그래야 개별조작 가능 -> 반영) List에 담아놓기
Car 코니;
Car 재성;
Cars cars;

@BeforeEach
void setUp() {
    코니 = new Car("코니");
    재성 = new Car("재성");
    cars = Cars.from(Arrays.asList(코니, 재성));
}

given자리에 단일객체 조작을! when에서는 일급컬렉 기능을!

  • given자리에 일급컬렉션과 공유된 개별 객체들을 조작후 -> 테스트한다.

      @Test
      void getMaxposition_method_test() {
          //given -> 단일객체를 조작
          코니.move(() -> true);
          재성.move(() -> false);
        
          //when
          Car actualMaxPositionCar = getMaxPositionCar2();
          //then
          assertThat(actualMaxPositionCar).isEqualTo(코니);
      }
        
      // private하며 메서드 내부의 메서드 ->  복사하고, 인자를 바꿔주자.
      private Car getMaxPositionCar2() {
          Car maxPositionCar = Arrays.asList(코니, 재성).stream()
              .max(Car::compareTo)
              .orElseThrow(() -> new IllegalArgumentException());
          return maxPositionCar;
      }