- 컴퓨터가 가진 데이터를 컴퓨터를 사용하는 사람들이 보고 다룰 수 있도록 만드는 과정을 의미한다.
- M은 Model을 의미한다. 모델은 데이터를 의미한다.
- V는 View를 의미한다. 뷰는 데이터가 보여지는 화면의 로직을 의미한다.
- C는 Controller를 의미한다. 컨트롤러는 모델의 데이터를 적절히 가공하여 뷰가 사용할 수 있도록 한다.
- 애플리케이션을 만들 때 크게 모델의 역할을 하는 부분과, 뷰의 역할을 하는 부분과, 컨트롤러의 역할을 하는 부분으로 분리하여 만드느 방법을 의미한다.
- 컴퓨터가 저장하고 있는 데이터는 사람이 직접 보기에 불편하고 해석이 안 되는 경우도 있다.
- 사람이 컴퓨터에 저장된 데이터를 사용하기 위해서는 적절하게 가공된 형태의 데이터를 취득할 필요가 있다.
- 컴퓨터에 저장되어 있는 데이터를 프로그래밍의 코드에서 사용할 수 있는 형태로 가져오는 부분이 모델이다.
- 동일한 데이터라도 어디에서는 표 형식으로 어떤 곳에서는 그래프 형식으로 어떤 곳에서는 어떤 글 안에 포함는 경우가 있다.
- 또한 동일한 데이터라도 모바일 앱에서 보여 줘야 할 때도 있고 웹 화면에서 보여줘야 할 때도 있다.
- 각 뷰는 서로 다른 코드 구성을 가질 때가 많고 동일한 데이터라도 각 뷰에서 사용할 수 있는 형태로 코드를 가공해야 뷰에 보여줄 수 있는 경우가 많다.
- 모델의 데이터는 서로 다른 코드 구성을 가진 뷰에 전달하기 위해서 데이터를 적절하게 가공하는 부분이다.
- 일반적으로 모델과 뷰는 각각 독자적인 포멧이 정해져 있기 때문에 모델에서 뷰로 데이터를 전달하기 위해서는 두 포멧 사이에 데이터 전달을 가능하게 하는 기능이 필요하고 이 부분이 컨트롤러의 역할에 해당한다.
- 프로젝트 최상위 경로의
examples폴더에patterOfMVC라는 폴더를 만들고onlyView라는 폴더를 만들고data.js,view.js,index.html파일을 만들자.
data.js
const data = [
'모델: 데이터와 비즈니스 로직을 관리합니다.',
'뷰: 레이아웃과 화면을 처리합니다.',
'컨트롤러: 명령을 모델과 뷰 부분으로 라우팅합니다.'
];- 일반적으로 데이터베이스 또는 파일로 부터 데이터를 가져오는 작업은 복잡하다.
- 여기에서는 간단히 예시를 들기 위해서 단순한 배열 형식의 데이터를 사용하였다.
view.js
const view = function () {
const modelVelue = data[0];
const viewValue = data[1];
const controllerValue = data[2];
return `
<div>
<div>${modelVelue.split(':')[0]}</div>
<div>${modelVelue.split(':')[1]}</div>
</div>
<div>
<div>${viewValue.split(':')[0]}</div>
<div>${viewValue.split(':')[1]}</div>
</div>
<div>
<div>${controllerValue.split(':')[0]}</div>
<div>${controllerValue.split(':')[1]}</div>
</div>
`;
}
const render = function (htmlTag) {
document.querySelector('body').innerHTML = htmlTag;
}
render(view())view함수는 HTML 태그의 문자열을 반환한다.render함수는body태그에 넣을 HTML 태그 문자열을 받아서 화면에 보여준다.render(view())는view()HTML 태그 문자열을 만들어서body태그에 넣어 준다는 의미이다.modelVelue.split(':')라는 코드는'모델: 데이터와 비즈니스 로직을 관리합니다.'라는 문자열을:문자를 기준으로 분리하여['모델', ' 데이터와 비즈니스 로직을 관리합니다.']라는 배열로 만든다.${modelVelue.split(':')[0]}는 배열의 첫 번째 값인'모델'이 출력되는 부분이고,${modelVelue.split(':')[1]}은 배열의 두 번째 값인' 데이터와 비즈니스 로직을 관리합니다.'가 나온다.
<body>
<script src="./data.js"></script>
<script src="./view.js"></script>
</body>- 간략하게 나타내기 위해 HTML의 다른 태그는 생략하였고 스크립트 파일만 로딩을 하였다.
- 데이터의 순서의 변경이 일어나면, 뷰에 보여지는 데이터도 변경이 된다.
'키워드 : 설명'이라는 데이터의 구조를 알아야 위의 코드를 이해할 수 있다.- HTML 태그에 들어간 자바스크립트 코드 때문에 위의 태그 구조가 정확히 무엇을 의미하는지 한 눈에 알기 어렵다.
- 프로젝트 최상위 경로의
examples폴더에patterOfMVC라는 폴더에서onlyView폴더를 복사하여clearView라는 폴더를 만들고data.js,view.js,index.html파일을 만들자. - 나머지 코드는 그대로이며
view.js의 코드만 다음과 같이 바꾸자.
const view = function () {
const modelValue = data[0];
const viewValue = data[1];
const controllerValue = data[2];
const modelDescription = {
title : modelValue.split(':')[0],
contents : modelValue.split(':')[1]
};
const viewDescription = {
title : viewValue.split(':')[0],
contents : viewValue.split(':')[1]
};
const controllerDescription = {
title : controllerValue.split(':')[0],
contents : controllerValue.split(':')[1]
};
return `
<div>
<div>${modelDescription.title}</div>
<div>${modelDescription.contents}</div>
</div>
<div>
<div>${viewDescription.title}</div>
<div>${viewDescription.contents}</div>
</div>
<div>
<div>${controllerDescription.title}</div>
<div>${controllerDescription.contents}</div>
</div>
`;
}
const render = function (htmlTag) {
document.querySelector('body').innerHTML = htmlTag;
}
render(view())modelDescription,viewDescription,controllerDescription라는 리터럴 오브젝트 3개를 만들었다.- HTML 태그 구조에 있던
modelValue.split(':')[0],modelValue.split(':')[1]코드가 리터럴 오브젝트 쪽으로 이동하였다.
<div>${modelVelue.split(':')[0]}</div>
<div>${modelVelue.split(':')[1]}</div>- 위의 코드는 첫 번째
<div>태그와 두 번째<div>태그 사이에 어떤 데이터가 들어갔는지 한 눈에 봐서 알수 없다.
const data = [
'모델: 데이터와 비즈니스 로직을 관리합니다.',
'뷰: 레이아웃과 화면을 처리합니다.',
'컨트롤러: 명령을 모델과 뷰 부분으로 라우팅합니다.'
];- 위와 같은 배열의 구조를 알아야 어떤 데이터가 들어가 있는지 알 수 있게 된다.
<div>${modelDescription.title}</div>
<div>${modelDescription.contents}</div><div>태그 안에 어떤 값이 들어가는지 알 수 없었지만, 위와 같은 방식을 이용해서 어떤 값이 들어갈지 좀 더 짐작하기 쉬운 코드를 쓸 수 있다.- 의미적으로 알기 쉽게 코드를 쓰는 것을 프로그래밍 언어에서는 가독성을 높인다고 한다.
- 프로젝트 최상위 경로의
examples폴더 하위의patterOfMVC라는 폴더에서withoutController라는 폴더를 만들고data.js,model.js,view.js,index.html파일을 만들자. data.js는 이전 파일 그대로 사용한다.
index.html
<body>
<script src="./data.js"></script>
<script src="./model.js"></script>
<script src="./view.js"></script>
</body>model.js
class Model {
constructor(data) {
this.data = data;
}
get modelData() {
return this.data.find(e => e.includes('모델'));
}
get controllerData() {
return this.data.find(e => e.includes('컨트롤러'));
}
get viewData() {
return this.data.find(e => e.includes('뷰'));
}
}- 모델은 데이터를 다룰 수 있는 기능을 제공한다.
- 위에서 클래스 문법을 사용했는데 우선 클래스에 대한 자세한 설명은 스킵한다. 일단 이런 게 있구나를 알고 넘어가도록 하자.
new model(data)라는 방법으로 클래스를 객체를 생성할 수 있다.cosnt modelObj = new model(data)로 오브젝트를 변수에 넣어modelObj.modelData,modelObj.viewData등의 방법으로 사용할 수 있다.new model(data)방법으로 사용하면 객체의 초기값으로 넣은data는 객체를 생성할 때 실행되는 함수인constructor함수에 객체를 생성할 때 받은data를 생성자 함수의 인자로constructor(data)와 같이 전달한다. 그리고this.data는 객체가 가지고 있는data변수이다. 객체가 가진this.data는 객체를 생성할 때 전달한data를 전달 받는다.data.find(e => e.includes('모델'))에서this.data는 객체를 생성new model(data)할 때this.data에data를 전달한다.data.js에서data변수는 배열이다.배열.find()문법은 배열에서 배열에 들어 있는 값을 차례로 확인하면서 첫번째로 매칭되는 대상을 찾는다.e.includes('모델')은 배열의 값 중에서'모델'이란 문자열이 들어간 대상을 찾아서 그 값을 반환한다.- 쉽게 말해서
modelData메소드(함수)는 data 배열에서'모델'이란 문자열이 들어간 배열을 찾는 메소드(함수)이며,controllerData메소드(함수)는 data 배열에서'컨트롤러'이란 문자열이 들어간 값을 찾는 메소드(함수)이며,viewData메소드(함수)는 data 배열에서'뷰'라는 문자열이 들어간 값을 찾는 메소드(함수)이다.
view.js
const view = function () {
const modelObj = new Model(data);
const modelValue = modelObj.modelData;
const viewValue = modelObj.viewData;
const controllerValue = modelObj.controllerData;
const modelDescription = {
title : modelValue.split(':')[0],
contents : modelValue.split(':')[1]
};
const viewDescription = {
title : viewValue.split(':')[0],
contents : viewValue.split(':')[1]
};
const controllerDescription = {
title : controllerValue.split(':')[0],
contents : controllerValue.split(':')[1]
};
return `
<div>
<div>${modelDescription.title}</div>
<div>${modelDescription.contents}</div>
</div>
<div>
<div>${viewDescription.title}</div>
<div>${viewDescription.contents}</div>
</div>
<div>
<div>${controllerDescription.title}</div>
<div>${controllerDescription.contents}</div>
</div>
`;
}
const render = function (htmlTag) {
document.querySelector('body').innerHTML = htmlTag;
}
render(view());new Model(data)는 클래스로 객체를 생성하는 문법이다.modelObj.modelData는data배열에서 모델 부분에 해당한는 데이터인'모델: 데이터와 비즈니스 로직을 관리합니다.'값이다.modelObj.viewData는data배열에서 뷰 부분에 해당한는 데이터인'뷰: 레이아웃과 화면을 처리합니다.'값이다.modelObj.controllerData는data배열에서 뷰 부분에 해당한는 데이터인'컨트롤러: 명령을 모델과 뷰 부분으로 라우팅합니다.'값이다.- 나머지는 앞선
view.js예제와 동일하다.
const modelVelue = data[0];
const viewValue = data[1];
const controllerValue = data[2];data배열에서 몇 번째에 위치하는 모델에 해당하는 데이터는 몇 번째 데이터인지, 뷰에 해당하는 데이터는 몇 번째인지, 컨트롤러에 해당하는 데이터는 몇 번째인지 일일이 확인해서 데이터를 넣었다.
const modelObj = new Model(data);
const modelVelue = modelObj.modelData;
const viewValue = modelObj.viewData;
const controllerValue = modelObj.controllerData;- 그에 반해 모델이 어떤 데이터를 가져 오는지 알려주기 때문에 데이터의 순서와 구조에 의존하지 않고 모델 데이터를 가져오고 싶을 때는
data[0]가 아닌modelObj.modelData를 쓰면 되고, 뷰 데이터를 가져오고 싶을 때는data[1]가 아닌modelObj.viewData를 쓰면 되고, 컨트롤러 데이터를 가져오고 싶을 때는modelObj.controllerData를 쓰면된다.
- 데이터 순서의 변경에 따라서 뷰의 데이터도 변경이 되는 문제점이 있었지만, 모델을 사용하면 데이터의 순서에 상관 없이 모델에 해당하는 데이터, 뷰에 해당하는 데이터, 컨트롤러에 해당하는 데이터를 원하는 대로 뽑아낼 수 있기 때문에 데이터의 나열 순서가 변경이 되어도 뷰에 표시되는 순서에 영향을 주지 않는다.
'키워드 : 설명'이라는 데이터의 구조를 알아야 위의 코드를 이해할 수 있다.'키워드 : 설명'문자열 데이터 구조를오브젝트.타이틀,오브젝트.내용이런 식으로 만드는 과정이 있는데 뷰에서 만들다 보니까 뷰의 코드가 길어져 버리는 문제가 생긴다.view()함수에서는 화면에 보여주는 구조에 대한 것만 최대한 보고 싶은데, 데이터를 가공하는 코드까지 보게 된다.
- 데이터를 가공하는 부분을 뷰에서 떼어서 컨트롤러로 옮겨보도록 하자.
- 컨트롤러는 컨트롤 하는 역할을 한다. 모델과 뷰를 사용하는 부분에 해당한다.
- 프로젝트 최상위 경로의
examples폴더 하위의patterOfMVC라는 폴더에서withController라는 폴더를 만들고data.js,model.js,view.js,controller.js,index.html파일을 만들자. data.js,model.js은withoutController폴더의 것과 동일한 것을 사용한다.
index.html
<body>
<script src="./data.js"></script>
<script src="./model.js"></script>
<script src="./view.js"></script>
<script src="./controller.js"></script>
</body>controller.js
class Controller {
constructor (model) {
this.model = model;
}
get modelDescription () {
const modelDataArray = this.model.modelData.split(':');
return {
title :modelDataArray[0],
contents : modelDataArray[1]
}
};
get viewDescription () {
const viewDataArray = this.model.viewData.split(':');
return {
title : viewDataArray[0],
contents : viewDataArray[1]
}
};
get controllerDescription () {
const controllerDataArray = this.model.controllerData.split(':');
return {
title : controllerDataArray[0],
contents : controllerDataArray[1]
}
};
}
const controllerObj = new Controller(new Model(data));
render(
view(
controllerObj.modelDescription,
controllerObj.viewDescription,
controllerObj.controllerDescription
)
);Controller클래스를 만든다. 컨트롤러 클래스는 컨트롤러 객체를 생성(new Controller(new Model(data))) 할 때model객체(new Model(data))를 전달 받아서 뷰에서 사용할 수 있는 형태로 바꿔주는 역할을 한다.- 컨트롤러 객체(
controllerObj)는 전달 받은 모델 객체를 가공한다. 예를 들어controllerObj.modelDescription부분은this.model모델을 전달 받아서 모델 안에 있는modelData를this.model.modelData으로 호출하고'모델: 데이터와 비즈니스 로직을 관리합니다.'데이터를 들고와서.split(':')으로:문자를 기준으로 데이터를 나누어:앞의 문자열은{}리터럴 오브젝트의title값으로,:뒤의 문자열은{}리터럴 오브젝트의contents값으로 할당한다. - 뷰에는 생성한 리터럴 오브젝트를 뷰 함수의 인자로
controllerObj.modelDescription,controllerObj.viewDescription,controllerObj.controllerDescription으로 전달한다.
view.js
const view = function (modelDescription, viewDescription, controllerDescription) {
return `
<div>
<div>${modelDescription.title}</div>
<div>${modelDescription.contents}</div>
</div>
<div>
<div>${viewDescription.title}</div>
<div>${viewDescription.contents}</div>
</div>
<div>
<div>${controllerDescription.title}</div>
<div>${controllerDescription.contents}</div>
</div>
`;
}
const render = function (htmlTag) {
document.querySelector('body').innerHTML = htmlTag;
}- 컨트롤러에서 가공한 데이터를 전달 받을 수 있는 형태로 만들기 위해서 함수의 인자 부분을 가공된 데이터를 받을 수 있는 형식으로 만들었다. 데이터를 함수의 인자로 받기 위해
function (modelDescription, viewDescription, controllerDescription)코드가 된 것
- 뷰에서 데이터를 가공하는 부분이 날라가서 뷰 코드는 뷰라는 역할에 맞게 HTML 태그 구조만 보여줄 수 있는 형태가 되었다.
- 화면에 관련된 것은
view에 데이터를 다루는 것은model에 뷰와 모델 간의 연결을 담당하는 부분은controller에서 담당한다. 각각은 화면에 관한 것, 데이터를 다루는 것, 연결을 담당하는 것 각자의 역할이 있다. 그리고 코드도 각자의 역할에 따라 나누었다. 이를 관심사의 분리라고 하고 이런 관심사의 분리의 대표적인 방법이 MVC 모델이다.