기존 코드에 MVC 패턴을 적용해보자

김나연·2022년 11월 21일
0
post-thumbnail

MVC 패턴으로 변경

프리 코스 미션을 하며 MVC 패턴에 대한 피드백을 받았다. 숫자 야구, 로또, 다리 미션 모두 MVC 패턴으로 바꿔 보았고 그 중 하나인 다리 미션이다. 내가 작성한 코드의 요구 사항과 기능 목록이다.

BridegeGame (Controller) -> Bridge (Model) -> InputView, OutputView (View)

처음 내가 작성한 코드에 MVC 패턴을 빗대어 본 모습이다. MVC 패턴을 생각하고 만든 코드가 아니기 때문에 몇 가지 문제점이 존재한다고 판단하였다.

MVC 패턴이란

MVC(Model-View-Controller) 패턴에서 Controller는 Model의 데이터를 조회하거나 업데이트하는 역할을 한다. Model이 업데이트 되면, View는 화면이 반영한다.

문제점

App.js

const model = new Model();
const Controller = new Controller();

View.readBridgeSize(bridge, bridgeGame);

View에 Model과 Controller을 넣어주고 View에서 모든 것을 처리하도록 해주었다. 내부적으로는 Controller가 Model을 처리하지만 App에서 보기에 MVC 패턴 역할이 맞지 않아 보인다.

OutputView.js

  printResult(bridgeGame) {
    MissionUtils.Console.print("최종 게임 결과");
    this.printMap(bridgeGame.getUpResult(), bridgeGame.getDownResult());
    MissionUtils.Console.print(
      `게임 성공 여부: ${(bridgeGame.getSuccess() && "성공") || "실패"}`
    );
    MissionUtils.Console.print(`총 시도한 횟수: ${bridgeGame.getAttempt()}`);
    MissionUtils.Console.close();
  }

OutputView에서 printResult를 보면 마찬가지로 Controller가 콘솔 출력에 사용되고 있다. Model이 업데이트되면 화면에 보여주는 것이 View니까, 결과 값을 매개 변수로 받아 결과가 출력되면 좋을 것 같다.

InputView.js

readMoving(bridge, bridgeGame) {
    MissionUtils.Console.readLine(TEXT.MOVEMENT, (movement) => {
      if (checkMovement(movement)) return this.readMoving(bridge, bridgeGame);

      bridgeGame.move(movement, bridge);
      OutputView.printMap(bridgeGame.getUpResult(), bridgeGame.getDownResult());

      this.isCrossing(bridge, bridgeGame);
    });
  },

View는 콘솔 출력과 화면 출력만 담당해야 하는데 this.isCrossing(bridge, bridgeGame) 처럼 controller가 담당할 만한 기능이 담겨있다. 심지어 입력 값만 관여해야하는 InputView 인데 출력만 해주는 OutputView가 사용되고 있다.

바꿔보기

App.js

class App {
  play() {
    const brideGame = new BrideGame();

    brideGame.game();
  }
}

BridgeGame.js

  gameStart() {
    OutputView.printStart();
    InputView.readBridgeSize(this.makeBridge.bind(this));
  }

  game() {
    this.gameStart();
  }

View는 Model을 보여주고 Controller는 Model을 업데이트 해준다. MVC 패턴에 좀 더 어울리게 바꿔보았다.

BridgeGame.js

  makeBridge(size) {
    const bridge = new Bridge();
    this.bridge = bridge;
    if (checkBridgeSize(size)) {
      return InputView.readBridgeSize(this.makeBridge.bind(this));
    }

    this.bridge.setBridge(size);
    console.log(this.bridge.getBridge());

    InputView.readMoving(this.move.bind(this));
  }

  doQuit() {
    OutputView.printResult(
      this.downResult,
      this.upResult,
      this.success,
      this.attempt
    );
  }

Controller로 Model 업데이트를 한 결과 값을 View에 넣어준다.

InputView.js

readMoving(callback) {
  MissionUtils.Console.readLine(TEXT.INPUT.MOVING, (movement) => {
    callback(movement);
  });
},

OutputView.js

printResult(downResult, upResult, success, attempt) {
  MissionUtils.Console.print("최종 게임 결과");
  this.printMap(upResult, downResult);
  MissionUtils.Console.print(
    `게임 성공 여부: ${(success && "성공") || "실패"}`
  );
  MissionUtils.Console.print(`총 시도한 횟수: ${attempt}`);
  MissionUtils.Console.close();
},

InputView와 OutputView의 각각의 기능을 명확히 하였다. InputView는 입력 값과 관련된 기능을 수행하고 OutputView는 화면 출력 값과 관련된 기능을 수행하면서 View가 담당하는 일만을 수행하고 있다.

전체 코드

https://github.com/kknyapple/javascript-bridge/tree/retry-bridge

https://github.com/kknyapple/javascript-baseball/tree/retry-baseballGame

https://github.com/kknyapple/javascript-lotto/tree/retry-Lotto

참고

  1. MDN
  2. 면접을 위한 CS 전공 지식 노트 1.1.8 MVC 패턴

0개의 댓글