티스토리 뷰

이번 포스팅에서는 MVC 패턴에 대해 이야기할 것이다. 제목에서도 나와있듯이 이론은 많은 블로그들에서 정의되어있어 찾아보기가 쉬울 것이다. 여기서는 이론보다는 실제 코드에 어떻게 MVC 패턴을 적용할 수 있는지 알아본다. 모든 내용은 테크톡을 참고하였다. 또한 모든 코드는 프리코스 3주차 로또 게임을 진행하면서 구현한 코드임을 알립니다. 

 

Model은 Controller와 View에 의존하지 않아야 한다.

첫번째 규칙은 Model은 Controller와 View에 의존하지 않아야 한다. 의존하지 않아야 한다라는 말을 바꿔 말하면 Model 내부에 Controller나 View와 관련된 코드가 존재해서는 안된다는 뜻이다. 그 이유는 Model은 데이터를 관리하는 곳이기 때문에, 사용자에게 보여지는 UI 로직이나 필요없는 Controller코드가 있다면 유지보수하기가 어려워지기 때문이다. MVC가 탄생한 이유는 유지보수 때문이다.

 

예시를 들어서 설명하겠다. 먼저 아래 코드는 첫번째 규칙을 지키지 않은 잘못된 예시다.

public class Buyer {
    private final List<Lotto> lottos;

    public Buyer() {
        lottos = new ArrayList<>();
    }

    public int buyLotto(String lottoAmount) {
        validatesLottoAmount(lottoAmount);
        generateLotto(Integer.parseInt(lottoAmount));
        return Integer.parseInt(lottoAmount);
    }

    public List<Lotto> getLottos() {
        return this.lottos;
    }

    private void generateLotto(int amount) {
        int count = countOfBuyLottos(amount);
        IntStream.range(1, count + 1).forEach(value -> lottos.add(Lotto.create()));
        OutputView.printPurchase(count, lottos);
    }

    private int countOfBuyLottos(int amount) {
        return (amount / DIVIDING_NUMBER);
    }
}

 

generateLotto 메서드를 자세히 보면 로또용지를 생성하고 바로 출력한다. 즉 View에 의존한 것이다. 

    private void generateLotto(int amount) {
        int count = countOfBuyLottos(amount);
        IntStream.range(1, count + 1).forEach(value -> lottos.add(Lotto.create()));
        OutputView.printPurchase(count, lottos);
    }

 

그럼 어떻게 의존을 낮출 수 있을까? 바로 Model과 View 둘 다 연관이 있는 Controller에 의존을 위임시키면 된다. 일단 먼저 위임시키기 전에 해야할 일이 있다. 

 

1. 기존 코드에서 필요했던 로또 구입 금액은 인스턴스 변수로 변경

public class Buyer {
    private final List<Lotto> lottos;
    private int lottoAmount;

    public Buyer() {
        lottos = new ArrayList<>();
    }

    public void buyLotto(String lottoAmount) {
        validatesLottoAmount(lottoAmount);
        generateLotto(Integer.parseInt(lottoAmount));
    }
    
    ...
    
}

 

2. View에서 사용할 수 있게 getter 구현

public int getLottoAmount() {
	return this.lottoAmount;
}

 

이제 Controller에 의존을 넘겨보자! 이미 Controller에서 Buyer객체를 생성했다고 생각하겠다. 

 

LottoController.java

buyer.buyLotto(Console.readLine);
OutputView.printPurchase(buyer);

 

이렇게 구현을 하게 되면 또 다른 규칙인 View가 Model로부터 데이터를 받을 때는 반드시 Controller에서 받아야 한다. 까지 지키는 것이다.

 

View가 Model로부터 데이터를 받을 때는 사용자마다 다르게 보여주어야 하는 데이터에 대해서만 받아야 한다.

당첨번호와 구매자의 로또용지에 적힌 번호를 계산하여 수익률을 계산하고 출력해야한다. 수익을 출력하는 함수는 다음과 같다.

public class OutputView {

    ...

    public static void printProfit(String START_PROFIT, double profit, String END_PROFIT) {
        System.out.println(START_PROFIT + Math.round(profit * 10) / 10.0 + END_PROFIT);
    }
}

 

 

위 코드에 문제점이 없어보이지만, 한 가지 문제점이 존재한다. 만약 A라는 사람이 로또를 구매하면 수익률을 보여준다. B라는 사람도 구매하면 수익률을 보여준다. 어느 누구라도 로또를 구매한다면 똑같이 수익률을 보여주어야 한다. 그런데 만약 출력형식을 매개변수로 받는다면, 유지보수면에서 엄청 힘들어질 것이다. 공통적인 부분은 View가 자체적으로 가지고 있어야 할 정보들이다. 따라서 다음과 같이 바꿔줄 수 있다. 

public class OutputView {
    public static final String START_PROFIT = "총 수익률은 ";
    public static final String END_PROFIT = "%입니다.";
    
    ...

    public static void printProfit(double profit) {
        System.out.println(START_PROFIT + Math.round(profit * 10) / 10.0 + END_PROFIT);
    }
}

 

앞에서 배운 규칙들을 기억하고 있다가 실제 코드에서 적용시킨다면 조금 더 요지보수하기 좋은 코드가 될 것이다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday