본문 바로가기
Java

[Java] 요구사항이 자주 변경되는 코드에 대한 리팩토링 / 전략 패턴 ( Strategy Pattern ) / 의존관계 주입(DI)

by bkuk 2023. 4. 24.

초기의 요구사항

package racing;

public class Car {
    private static final int FORWARD_NUM = 4;
    private static final int MAX_BOUND = 10;
    private String name;
    private int position;
    
    public void move(int number) {
        if( isMove(number) ) {
            this.position += 1;
        }
    }
    
    private boolean isMove(int number) {
        return number >= MIN_FORWARD_NUMBER;
    }
    //생략..
}

 

Car 라는 클래스는 Car의 이름을 의미하는 멤버변수 'name' Car의 위치를 의미하는 멤버변수 'position'이 존재한다. move() 메서드 호출 시 Random 클래스를 통해서 생성된 정수 0 ~ 10 사이의 무작위 숫자가 FORWARD_NUM(4)보다 크냐, 작냐에 따라서 멤버 변수 position이 1이 증가하느냐, 증가하지 않느냐가 결정된다.

만약, 무작위 숫자가 아닌 짝수일때는 전진, 홀수일때는 정지 혹은 오전일때는 전진, 오후일때는 정지 등..으로 요구사항이 자주 변경된다고 가정해보자.

 

인터페이스로 변경할 로직을 확인하자.

// number >= MIN_FORWARD_NUMBER을 의미함.
isMove(number)

 

그렇다면, 위 로직을 완전히 독립된 인터페이스로 분리하는 것이 좋다.

 

인터페이스로 추출하자.

public interface MovingStrategy {
    boolean movable();
}
    public void move(MovingStrategy movingStrategy) {
        if( movingStrategy.movable() ) {
            this.position += 1;
        }
    }
    @Test
    void 자동차_전진_레거시_리팩토링() {
        Car car = new Car("pobi");
        car.move(new MovingStrategy() {
            @Override
            public boolean movable() {
                return true;
            }
        });
        assertThat(car.getPosition()).isEqualTo(1);
    }
    
    @Test
    void 자동차_정지_레거시_리팩토링() {
        Car car = new Car("pobi");
        car.move(new MovingStrategy() {
            @Override
            public boolean movable() {
                return false;
            }
        });
        assertThat(car.getPosition()).isEqualTo(0);
    }

인터페이스의 추상 메서드를 위와 같이 구현함으로써, 테스트 가능한 구조로 변경할 수 있다.

실제 구현하는 프로덕션 코드에서는 아래와 같이 MovingStrategy를 구현한 RondomMovingStrategy 클래스를 사용할 수 있다.

public class RandomMovingStrategy implements MovingStrategy {
    private static final int MIN_FORWARD_NUMBER = 4;
    private static final int MAX_BOUND = 10;
    
    @Override
    public boolean movable() {
        return isMove(getRandomNo());
    }
    
    private int getRandomNo() {
        Random random = new Random();
        return random.nextInt(MAX_BOUND);
    }
    
    private boolean isMove(int number) {
        return number >= MIN_FORWARD_NUMBER;
    }

 

이러한 방법을 의존관계를 주입하는 방법으로 볼 수 있으며, 이를 DI라고 할 수 있다.

 

 

댓글