ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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메서드로 뺄 수 도 있는데, 여기선 굳이 필요없다.

    테스트하기 쫌 편해지는 감이 있다. 

Designed by Tistory.