<MVC 패턴> - Model, View, Controller로 구성된 디자인패턴
- Model
-> 게임 기능에 관한 로직을 처리한다.
-> 결과값을 Controller에게 전달한다.
-> view와 Controller에 대한 정보를 가지고 있지 않는다.
- View
-> UI를 보여주는 역할을 한다.
-> 이때 모델이 처리한 결과를 가지고 화면을 출력하며 이 데이터는 Controller에서 받아온다.
- Controller
-> 사용자의 입력에 반응한다.
-> Model과 View 사이에 존재하며 데이터를 전달한다
<MVC 패턴 적용한 코드>
- 이전 코드
우선 지난번에 MVC는 고려하지 않고 기능만 고려를 해서 더럽게 짰던 코드를 수정하여 바꿔보도록 하겠다. 아래 링크로 가면 이 전 코드를 확인할 수 있다.
[JS] 숫자야구게임 기능 구현하기 (1)
그동안 제대된 동아리나 협업활동을 해본적이 없었는데 올해 프론트엔드 분야로 공부를 해보고 싶어 새롭게 동아리를 들어갔다. 항상 혼자서 이리저리 조금씩 껄떡대며 공부를 하긴 했었지만
zldn.tistory.com
- 전반적인 수정 사항
> 함수의 이름이나 변수를 조금 더 기능이 명확하게 보이게 함수명을 바꾸고 또한 기능에 맞춰 세분화하여 변경
> 게임 진행관련과 이벤트리스너는 Controller(GameController.js)로 모두 이동
> 게임 로직과 관련된 것들은 Model(BaseballGame.js)로 이동
> 화면에 출력하는 것들은 View(GameView.js)로 이동
> Model에서 결과값을 Controller로 반환하고 Controller에서 그 결과값을 View로 보내도록 수정
- MVC를 적용하여 작성한 흐름
1. index.js에서는 Controller를 호출하는 역할만 한다.
//실행(index.js)
import { gameStart } from "./GameController.js"
gameStart();
2. Controller가 호출되면 게임을 초기화하고 Model과 View의 인스턴스를 생성한다.
//GameController.js
import BaseballGame from "./BaseballGame.js";
import GameView from "./GameView.js"
let game;
let view;
export function gameStart() {
game = new BaseballGame();
view = new GameView();
view.resetGameUI();
setEventListeners();
}
3. Controller에서 이벤트리스너를 이용해 사용자입력과 게임 재시작 이벤트를 처리한다.
//GameController.js
function setEventListeners() {
const form = document.querySelector("form");
form.addEventListener("submit", processUserInput);
const replay = document.querySelector("#game-restart-button");
replay.addEventListener("click", gameStart);
}
4. 사용자가 입력을 제출하면 Controller는 유저인풋 값을 Model에 전달한다.
//GameController.js
function processUserInput(event) {
event.preventDefault();
let userInput = document.getElementById("user-input").value;
let comparisionResult = game.handleUserInput(userInput);
if (comparisionResult === "3스트라이크") {
view.displaySuccessMessage();
} else {
view.displayResultMessage(comparisionResult);
}
}
5. Model은 유저인풋값이 조건에 맞는지 확인하고 랜덤정수(정답)과의 비교를 통해 결과 메세지를 생성하여 Controller에 반환한다.
-> 이때 BaseballGame은 class로 묶어서 구성했다.
//Model
export default class BaseballGame {
constructor() {
this.computerNumbers = this.getRandomNumberString();
}
getRandomNumberString() {
let randomNumber = [];
while (randomNumber.length < 3) {
let num = MissionUtils.Random.pickNumberInRange(1, 9);
if (!randomNumber.includes(num)) {
randomNumber.push(num);
}
}
randomNumber = randomNumber.join("");
return randomNumber;
}
handleUserInput(userInput) {
if (this.checkUserInput(userInput)) {
return;
}
const comparisionResult = this.compareInputWithAnswer(userInput);
return comparisionResult;
}
compareInputWithAnswer(userInput) {
let strikeCount = 0, ballCount = 0;
for (let i = 0; i < 3; i++) {
if (userInput[i] === this.computerNumbers[i]) { //스트라이크
strikeCount++;
}
else if (this.computerNumbers.includes(userInput[i])) { //볼
ballCount++;
}
}
return this.play(strikeCount, ballCount);
}
play(strikeCount, ballCount) {
let resultMessage = "";
if (ballCount > 0) {
resultMessage += `${ballCount}볼 `;
}
if (strikeCount > 0) {
resultMessage += `${strikeCount}스트라이크`;
}
if (ballCount == 0 && strikeCount == 0) {
resultMessage = "낫싱";
}
return resultMessage;
}
checkUserInput(userInput) {
const isNotNumber = isNaN(userInput);
if (isNotNumber) {
alert("잘못된 값을 입력했습니다.\n숫자를 입력해주세요.");
return true;
}
else if (userInput.length !== 3) {
alert("잘못된 값을 입력했습니다.\n세자리 숫자를 입력해주세요");
return true;
}
else if (new Set(userInput).size !== 3) {
alert("잘못된 값을 입력했습니다.\n중복되지않는 세자리 숫자를 입력해주세요.");
return true;
}
return false;
}
}
6. Controller는 반환받은 결과 메세지를 View에 전달한다.
//Controller.js의 processUserInput(event)함수 내부의 일부
if (comparisionResult === "3스트라이크") {
view.displaySuccessMessage();
} else {
view.displayResultMessage(comparisionResult);
}
7. View는 Controller로부터 Model의 결과값을 전달받아 화면을 출력한다.
-> 이때 View는 class로 묶어서 구성했다.
//GameView.js
export default class GameView {
displaySuccessMessage() {
document.querySelector("#result").style.display = "none";
document.querySelector(".success").style.display = "block";
const submitBtn = document.querySelector("#submit");
submitBtn.disabled = true;
}
resetGameUI() {
const submitBtn = document.querySelector("#submit");
submitBtn.disabled = false;
document.querySelector(".success").style.display = "none";
}
displayResultMessage(comparisionResult) {
let gameResult = document.querySelector("#result");
gameResult.style.display = "block";
gameResult.textContent = comparisionResult;
}
}
8. 정답을 맞추게 되면 Controller에서 이벤트리스너를 이용하여 재시작버튼에 대한 클릭이벤트를 감지하고 게임을 다시 실행하도록 한다.
//GameControlller.js에서 setEventListeneners() 함수 내의 일부
const replay = document.querySelector("#game-restart-button");
replay.addEventListener("click", gameStart);
'프로젝트 > 숫자야구게임' 카테고리의 다른 글
[JS] 숫자야구게임 기능 구현하기 (1) (0) | 2025.03.22 |
---|