프리 코스 미션을 하며 MVC 패턴에 대한 피드백을 받았다. 숫자 야구, 로또, 다리 미션 모두 MVC 패턴으로 바꿔 보았고 그 중 하나인 다리 미션이다. 내가 작성한 코드의 요구 사항과 기능 목록이다.
BridegeGame (Controller) -> Bridge (Model) -> InputView, OutputView (View)
처음 내가 작성한 코드에 MVC 패턴을 빗대어 본 모습이다. MVC 패턴을 생각하고 만든 코드가 아니기 때문에 몇 가지 문제점이 존재한다고 판단하였다.
MVC(Model-View-Controller) 패턴에서 Controller는 Model의 데이터를 조회하거나 업데이트하는 역할을 한다. Model이 업데이트 되면, View는 화면이 반영한다.
const model = new Model();
const Controller = new Controller();
View.readBridgeSize(bridge, bridgeGame);
View에 Model과 Controller을 넣어주고 View에서 모든 것을 처리하도록 해주었다. 내부적으로는 Controller가 Model을 처리하지만 App에서 보기에 MVC 패턴 역할이 맞지 않아 보인다.
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니까, 결과 값을 매개 변수로 받아 결과가 출력되면 좋을 것 같다.
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가 사용되고 있다.
class App {
play() {
const brideGame = new BrideGame();
brideGame.game();
}
}
gameStart() {
OutputView.printStart();
InputView.readBridgeSize(this.makeBridge.bind(this));
}
game() {
this.gameStart();
}
View는 Model을 보여주고 Controller는 Model을 업데이트 해준다. MVC 패턴에 좀 더 어울리게 바꿔보았다.
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에 넣어준다.
readMoving(callback) {
MissionUtils.Console.readLine(TEXT.INPUT.MOVING, (movement) => {
callback(movement);
});
},
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