생성자와 일급컬렉션(사용이유, 테스트)
네오의 TDD 강의(문자열계산기)+TIP
📜 제목으로 보기
생성자 규칙
나만의 규칙
- 생성 루트가 여러개 ex>
List<String>
orList<Car>
인 일급컬렉션- private 필요속성(만) 받는 기본생성자
- public
fromStrings( List< String > )
- inputView에서 검증을 하고 오므로 검증없이 ->
List<객체>
로 변환 -> 생성자
- inputView에서 검증을 하고 오므로 검증없이 ->
- public
from객체(List< 객체 >)
- test등에서 단일객체 -> List add되어 들어오는데, 복수 검증(중복)을 추가후 -> 생성자
-
VO, 단일객체
라도숫자형
이라면 ->inputView에서 형변환
후, 해당형으로 검증되도록- inputView에서 따로 검증안한다면, public 생성자에서 검증까지 다 처리하면 될 듯함.
- inputView에서는 VO는
형변환하고나서 -> 검증
하자.
- inputView에서는 VO는
- inputView 검증해야하는 상황이라면? -> 형변환후 int만 검증
- public 기본생성자(원본 타입) with 노검증(for
inputView거친 뒤 controller
or숫자VO 연산
) - public fromNumber(원본타입) with 검증(for 테스트 or int직접생성)
- public 기본생성자(원본 타입) with 노검증(for
- inputView에서 따로 검증안한다면, public 생성자에서 검증까지 다 처리하면 될 듯함.
일급컬렉션 생성자와 사용이유
생성자 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;
- cf) 일급컬렉션에
-
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; }