-
nextStep - 자동차 경주 일급 컬렉션 만들기언어/JAVA 2023. 7. 23. 10:54
- 일급 컬렉션을 통해 List를 감싸두면, 외부에서 List에 모든 인터페이스 접근 안하고, 필요 기능만 제공할 수 있다.
public class RacingGame { private List<Car> cars; private int tryNo; public RacingGame(String carNames,int tryNo){ this.cars = initCars(carNames); this.tryNo = tryNo; } private List<Car> initCars(String carNames) { if(StringUtils.isBlank(carNames)){ throw new IllegalArgumentException("자동차 이름 없어요"); } String[] names = carNames.split(","); List<Car> cars = new ArrayList<>(); for(String name : names){ cars.add(new Car(name)); } return cars; } public void race(){ this.tryNo--; moveCars(); } private void moveCars() { //이쪽에 랜덤값을 만들어서 전달하는 방식으로 //오브젝트 그래프 옮기기 가능 for(Car car: cars){ car.move(); } } public boolean racing(){return this.tryNo>0;} }
> List<Car> cars를 Cars클래스로 분리하자
public class Cars { private List<Car> cars; public Cars(List<Car> cars) { this.cars = cars; } }
1. WinnerTest 작성
*@Test void winner(){ Car boni = new Car("boni"); boni.move(); boni.move(); Car pobi = new Car("ss"); pobi.move(); pobi.move(); Car ho = new Car("ho"); ho.move(); List<Car> origin = Arrays.asList(boni,pobi,ho); Cars cars = new Cars(origin); assertThat(cars.findWinner()).containsExactly(pobi,boni); }
* 이때 Car생성자와 잘 분리된 끌래스여서 move메시지 계속 보내줘야함 -> 귀찮으니 잠깐만 변경
public Car(final String name){ this(name,0); } public Car(String name, int pos) { this.name = new CarName(name); this.pos2 = new Position(pos); }
1.2 Cars클래스에 메서드 만들기
public List<Car> findWinner() { int maxPos = 0; for(Car car : cars){ if(maxPos < car.getPos()){ maxPos = car.getPos(); } } List<Car> winners= new ArrayList<>(); for(Car car : cars){ if(car.getPos() == maxPos) winners.add(car); } return winners; }
* 간단 구현으로 리펙토링이 필요하다
-> 문제점 Car에 pos는 int가 아님! maxPos는 int가 아닌 Position이어야함
-> car에서 getPos()하는 부분은 지양해야함! 메시지 보내는 방식으로 바꾸자
-> 메서드 단위로 분리할 필요가 있다.
리팩토링 1
public List<Car> findWinner() { return getWinnerList(getMaxPos()); } private List<Car> getWinnerList(int maxPos) { List<Car> winners= new ArrayList<>(); for(Car car : cars){ if(car.isWinner(maxPos)) { //getter없애기 위해 메시지 보내는 형식으로 바꾸기 winners.add(car); } } return winners; } // car 클래스 public boolean isWinner(int maxPos) { return pos.isSame(maxPos); // 또 넘겨주기 } // pos 클래스 public boolean isSame(int maxPos) { return pos == maxPos; }
//cars private Position getMaxPos() { Position maxPos = new Position(); for(Car car : cars){ maxPos = car.getMaxPos(maxPos); } return maxPos; } //car클래스에 추가 public Position getMaxPos(Position maxPos) { if(this.pos.lessThan(maxPos)) return maxPos; return this.pos; } //pos 클래스에 추가 public boolean lessThan(Position maxPos) { return maxPos.pos > this.pos; }
* setter와 getter안쓰도록 계속 변경하고, 클래스에 메시지 보내는 형식으로 바뀜
* 메시지를 보내는 방식을 사용하면, 객체에서 값을 직접 꺼내서 비교하는 로직을 객체 안으로 집어 넣을 수 있다.
* 로직에 책임을 타 객체로 전가할 수 있다는 것
(ex cars에서 List에 들어있는 차가 승자인지 아닌지는 구별하는 로직은 필요없다 단지 승자만 담으면된다
승자인지 아닌지 구분하는 로직은 car안으로 집어넣자 -> car에 메시지 보내기 너 승자야?)
** Position에 int필드는 private이다. 외부 참조변수로 접근 불가 (클래스 안에서만 접근가능)
> 클래스 메서드 안에 외부에서 주어진 (매개변수)가 해당 클래스의 인스턴스라면, 당연히 접근가능
> 참조변수를 통해 접근할 수 있는 범위를 제한한 것이 접근제한자
-- 클래스 안에서 접근하는 것이니 가능
> 필드와 메서드에 접근제한자는 외부에서 해당 클래스 참조변수로 접근할 수 있는 필드와 메스드를 제한한 것 뿐
클래스 내부에선 기본적으로 해당 참조변수로 모두 접근 가능
*추가
public List<Car> findWinner() { return getWinnerList(this.cars, getMaxPos()); } public static List<Car> getWinnerList(List<Car> cars,Position maxPos) { List<Car> winners= new ArrayList<>(); for(Car car : cars){ if(car.isWinner(maxPos)) { //getter없애기 위해 메시지 보내는 형식으로 바꾸기 winners.add(car); } } return winners; }
static메서드로 뺄 수 도 있는데, 여기선 굳이 필요없다.
테스트하기 쫌 편해지는 감이 있다.
'언어 > JAVA' 카테고리의 다른 글
Java - File클래스 (0) 2023.07.24 Java - io 직렬화(Serialization) (0) 2023.07.24 nextStep - 모든 원시값과 문자열 포장 (0) 2023.07.23 nextstep-자동차경주 (테스트하기 어려운 코드 테스트하기) (0) 2023.07.23 람다식(3) - 최종처리 (0) 2023.07.14