728x90

스테이트 패턴 적용기

모든 코드는 깃허브에 있음을 알린다.

현재 패스트캠퍼스의 디자인 패턴 강의를 수강도 하고있고, 동시에 디자인 패턴에 대한 책도 한권 읽었었다.

그러니까 메인 메소드만 있는곳에서 디자인패턴을 적용하여 연습을 조금 했었다.

그리고 프로젝트에 도입을 했었는데 약간 2% 부족한 패턴이 탄생했었다.

지금에서의 완벽한 디자인패턴

프로젝트를 통해서 유저 포인트를 조건에 따라 변경해주는 로직이 있었다.

스크린샷 2021-10-06 오후 11 19 38

자... 예전의 나는 보잘 것 없었다.

ㅋㅋㅋㅋ 이게 그때 당시의 나에겐 최선이었을지도??

아무튼 각설하고 저 로직을 이제 바꿔보려고 한다.

해당로직의 bean이라는 객체는 단지 저 포인트와 해당 유저의 아이디만 가지고 있는 일종의 DTO이고,

네이밍마저 가독성을 해쳤다.

이제부터 리팩토링 과정을 적어보려고 한다.

리팩토링 과정

스크린샷 2021-10-06 오후 11 31 24

어설프지만 클래스 다이어그램을 그려보았다.

일단 PointState가 최종적으로 저 4개의 랭크들을 주입받아 사용하기 때문에 화살표를 그어주지는 않았다.

예전 방식으로는 저 클래스 하나하나마다 빈을 등록해주고 switch를 배제한대신 if문에 return방식으로 구현했다. 물론 뒷단으로 로직을 빼긴했지만 뒤지다보면 어찌됐든 나오게 되어있는 방식이었다...

일단 어떻게 구현했는지 하나하나 보도록하자

일단 기본 틀이되는 Rank부터 살펴보자

Rank.java

public interface Rank {
    int getRankEnum();
    int giveUserPoint();
}

랭크를 확인할 수 있는 로직과, point를 세팅해주는 로직이 있다.

RankEnum.java

@Getter
@NoArgsConstructor
@AllArgsConstructor
public enum RankEnum {
    FIRST(1),
    SECOND(2),
    THIRD(3),
    ANOTHER(-1);

    private int rank;
}

랭크별 enum을 관리하기로 생각해서 따로 빼주었다.

public class First implements Rank {

    @Override
    public int getRankEnum() {
        return RankEnum.FIRST.getRank();
    }

    @Override
    public int giveUserPoint() {
        return 3000;
    }

}

나머지 클래스들은 안에 반환값만 다르기 때문에 First만 가져오겠다.

PointState.java

public class PointState {
    private final Map<Integer, Rank> pointStateMap = new HashMap<>();

    public PointState(List<Rank> ranks) {
        ranks.forEach(rank -> {
            pointStateMap.put(rank.getRankEnum(), rank);
        });
    }

    public Rank getPointStateMap(int rank) {
        return pointStateMap.get(rank);
    }

}

구현체인 PointState이다.

@Configuration
public class RankConfig {

    @Bean
    public PointState pointState() {
        return new PointState(Arrays.asList(new First(), new Second(), new Third(), new Another()));
    }

}

나는 이렇게 Config 클래스에서 런타임때에 초기화를 해주는데 생성자의 형식에 맞게
Rank에 해당하는 4가지 구현체를 넣어주었다.
이제 int형의 랭크 등급에 따라 추가할 포인트값을 받을 수 있게 되었다.

이제는 이게 정상적으로 동작하는지 확인을 해보기 위해 테스트코드를 먼저 짜도록 해보겠다.

테스트코드 작성

PointState.java

@SpringBootTest(classes = RankConfig.class)
class PointStateTest {

    @Autowired
    PointState pointState;

    @Test
    void test() {
        Rank rank = pointState.getPointStateMap(RankEnum.FIRST.getRank());

        assertThat(rank.getRankEnum()).isEqualTo(RankEnum.FIRST.getRank());
        assertThat(rank.giveUserPoint()).isEqualTo(3000);
    }

}

Rank설정을 해준 RankConfig를 가져온 후에 적용시켰다.

그렇지 않으면 마이바티스가 섞여있기 때문에 지금 에러가 발생한다 😱

스크린샷 2021-10-06 오후 11 44 16

정상적으로 통과하는것을 볼 수 있다.

이제 switch 로직을 리팩토링 할 생각이다.

스크린샷 2021-10-06 오후 11 45 29

이렇게 바꾸었고 이제 조건에 분기하여 포인트 값을 할당하지 않고 바로 작업할 수 있게 되었다!!!

정리

스크린샷 2021-10-06 오후 11 19 38

이랬던 로직이

스크린샷 2021-10-06 오후 11 45 29

이렇게 바뀐거 보고 디자인패턴 정말 좋다고 느낀다.

하나하나 배우면서 계속 적용해보고 싶어지는게 당연하달까..

아무튼 좋은 경험이었고 프로젝트 리팩토링이 잘되어가는것 같다 👍

728x90

'Java' 카테고리의 다른 글

일급 컬렉션  (0) 2022.08.09
변수  (0) 2022.08.07
프로젝트 리팩토링  (0) 2022.08.07
디자인 패턴 - Bridge Pattern  (0) 2022.08.07

+ Recent posts