본문 바로가기
우아한테크코스/공부

[자동차 경주 미션] 전략 패턴 사용 후기

by 자바지기 2022. 2. 18.
반응형

자동차 경주 미션 과정 진행 중에 전략 패턴을 사용해보고 작성하는 글

Car 객체가 조건을 만족할 시 움직이는 기능을 구현하기 위해서 레벨 1단계에서는 다음과 같이 구현을 하였다.

public void move(int number) {
    if (number >= MOVING_CONDITION_NUMBER) {
	position += 1;
    }
}

 

이 메서드에 대한 테스트는 다음과 같다.

@Test
public void 전진_여부() {
    Car testCar = new Car("아스피", 2);
    testCar.move(4);
    assertThat(testCar.isSamePosition(new Car("배카라", 3))).isEqualTo(true);
}

 

위와 같이 move라는 메서드에 직접 값을 삽입하여 전진 여부를 결정하는 테스트를 작성하였다.

이 move 메서드를 이용한 테스트는 잘 동작하였지만 약간의 어색함이 있다.

  • move와 number는 무슨 관계이지?
  • 만약 이동 조건이 바뀐다면 이 코드는 어떻게 수정해야 하지?

 

그래서 이 문제를 해결하기 위해서 전략 패턴을 사용하였다.

일단 전략 패턴을 사용하기 위해 인터페이스를 하나 만들었다.

@FunctionalInterface
public interface MovingCarStrategy {
    boolean canMove();
}

 

그리고 이 인터페이스를 다음과 같이 Car의 필드 변수로 추가하였다.

public class Car {
    private final String name;
    private int position;
    private MovingCarStrategy movingCarStrategy;

 

이때 canMove 메서드를 사용하려면 MovingCarStrategy 인터페이스의 구현체가 필요한데

이를 구현한 클래스는 다음과 같이 작성하였다.

public class RandomMovingStrategy implements MovingCarStrategy {
   private static final int MOVING_CONDITION_NUMBER = 4;

   @Override
   public boolean canMove() {
       return getRandomNumber() >= MOVING_CONDITION_NUMBER;
   }

   private int getRandomNumber() {
       return (int) (Math.random() * 10);
   }
}

이 구현체에서 canMove 메서드는 랜덤 값이 4 이상일 경우 true를 반환한다.

 

이 구현체는 생성자를 통해 전달하였다.

public Car(String name, MovingCarStrategy movingCarStrategy) {
    this(name, 0);
    this.movingCarStrategy = movingCarStrategy;
}

 

이제 앞선 두 가지 문제 상황을 고려해 move 메서드를 다시 작성해보면 다음과 같다.

public void move() {
   if (movingCarStrategy.canMove()) {
       position += 1;
   }
}

 

이 메서드에는 별다른 매개변수를 넣어줄 필요 없이 canMove 메서드의 결과에 따라 이동 여부를 확인할 수 있다.

그리고 이동 조건이 바뀔 경우, 앞서 생성자를 통해 RandomMovingStrategy 객체를 전달한 것처럼

새로운 조건이 담긴 객체를 생성하여 전달하면 쉽게 코드를 수정할 수 있게 된다.

public class OtherMovingStrategy implements MovingCarStrategy {

   @Override
   public boolean canMove() {
       return ...
   }
}

위와 같이 새로운 클래스를 생성하여 Car 생성자를 통해 주입시켜주면 된다.

이처럼 전략 패턴을 사용하여 코드의 가독성을 챙겼고,

코드의 확장에는 열려있고 변경에는 닫혀 있는 개방 폐쇄 원칙을 따르는 구조를 갖게 되었다.

 

여러 전략을 선택해서 사용해야 할 때 전략 패턴을 사용하면 보다 좋은 방법으로 구현할 수 있을 것 같다.

반응형

댓글