[Node] 000 pattern

silverKi·2023년 12월 21일
0

Node

목록 보기
4/6

What's pattern.?

'디자인 패턴'에는 여러 종류의 패턴이 존재한다.
ooo패턴,, ooo패턴, 뭐가 많은데 패턴이 뭐고, 왜 필요한 거야.?

패턴이란, 각각 다른 기능에 따라 코드를 나누는것을 의미한다.
즉, code의 여러 부분들이 각기 다른 기능을 가져 어떤 부분이 어떤 작업을 책임지고 있는지 확실히 하는 것이다.

이렇게 하면, 패턴을 통해 효율적으로 일을 처리할 수 있다.
효율에는 개발자간의 협업이라든지, 논리 처리 과정 등이 포함될 것 같다.


여러 많은 디자인 패턴이 있지만, 대표적으로 MVC Pattern에 대해 서술해보려고 한다.


What's MVC pattern.?

MVC는 Model + View + Controllers의 약자이다.

모델은 기본적으로 객체나 데이터를 나타내는 부분으로, 데이터를 저장하거나 파일로부터 데이터를 주고 받는 등의 데이터 관련 작업을 할 수 있도록 한다.

는 사용자가 보게 되는 화면을 책임진다.
html자료에 올바른 내용을 렌더링하여 사용자에게 보내는 역할을 한다. 애플리케이션 코드와 분리되어 있으며, 뷰를 생성하기 위해 템플릿 엔진에 주입하는 데이터와 약간(?)만 통합되어 있다.

컨트롤러는 모델과 뷰의 연결점이다.
그 이유는 뷰는 애플리케이션 논리와 상관이 없으며, 모델은 데이터를 저장하고 가져오는 역할을 하기 때문에 컨트롤러가 모델과 함께 데이터를 저장하거나 저장 프로세스를 유발한다. 또한 뷰에서 가져온 데이터를 전달하는 경우에도 컨트롤러가 도와준다. 즉, 컨틀롤러는 "중개인"으로 중간 논리를 처리한다.
아래 코드에서 .get("/", (req, res, next) => {..});에는 모델과 데이터를 교류하는 부분과 뷰를 렌더링 하는 부분이 혼합되어 있다. 나는 이 코드를 모델을 이용해 객체를 정의하고 뷰를 렌더링하는 부분을 따로 분리해 controllers folder에 따로 정의하고자 한다.

const express = require("express");
const path = require("path");
const router = express.Router();
const rootDir = require("../util/path");
const adminData = require("./admin");

router.get("/", (req, res, next) => {
	const products = adminData.products; //동적 컨텐츠 렌더링~> data 교류
    res.render("shop", { //뷰를 렌더링
        prods: products,
        docTitle: "Shop",
        path: "/",
        hasProducts: products.length > 0,
        activeShop: true,
        productCSS: true,
        
	}); //shop template rendering
});

module.exports = router;

그럼 컨트롤러와 라운터는 뭐가 다른거지.?

라우터는 어떤 경로에 따른 http method에 따라, 어떤 컨트롤러 코드를 실행할지 결정한다.

app.get('/test', (req, res, next)=>{
	res.send("<h1>GET Method test</h1>")
});
app.post('/test', (req, res, next)=>{
	res.send("<h1>POST Method test</h1>")
});

라우터는 /test 경로로 들어오는 사용자에게 해당하는 view를 보여주고, 만약 사용자가 해당 경로내에서 post 요청에 해당하는 작업을 한 경우에만, POST Method test 뷰를 작성하는 컨트롤러를 선택해 이때 컨트롤러가 뷰와 모델 사이의 작업을 중개할 것이다. 따라서 컨트롤러는 미들웨어 기능간에 분할이 된다.


Controller

routesfolder안에, 모델과 데이터 교류하고 뷰를 렌더링하는 일련의 과정을 모두 작성하게 되면, routes folder가 아주 비대해 질것이다. 따라서 해당 루트 폴더에 controllers폴더를 추가한다.

이렇게 하면, 어떤 파일에 어떤 라우터가 존재하는지 각 처리 역할은 무엇인지 해당하는 컨트롤러 파일과 함수에서 쉽게 파악할 수 있다.

이때 라우트 파일이름 또는 파일 번호와 컨트롤러 파일을 일대일로 맵핑 할 수 있고, 또는 일정 양식에 따라서 라우트를 그룹화 할 수도 있다.

//router/shop.js

const productsController = require('../controllers/products')
router.get("/", productsController.getProduct);

module.exports = router;

//controllers/products.js

exports.getProduct = (req, res, next) => {
    res.render("shop", {
        prods: products,
        docTitle: "Shop",
        path: "/",
        hasProducts: products.length > 0,
        activeShop: true,
        productCSS: true,
        
	});
}

router안에 존재했던 모델과 data를 교류하는 부분과, 뷰를 렌더링하는 부분을 분리한 다음, controller에 뷰를 렌더링하는 부분을 옮겨 router 파일이 비대해지는것을 방지할 수 있게 된다. 또한 router에 controller의 참조값을 전달하기 위해 모듈을 export해준다.

Model

//models/product.js

const products = [];

module.exports = class Product { 
    constructor(t) { //매개변수 : title 
        this.title = t //this.title을 인수로 수신함
        //this == Product 객체를 가리킴
    }
    save() { 
        products.push(this)
    }
    static fetchAll() { 
        return products
    }
}

모델을 정의하기 위해 models folder를 생성하고 파일을 만든다.
나는 Product 모델을 만들기 위해 class를 생성하고 생성자 함수를 이용하여 속성을 정의 했다.

제품명에 해당하는 title을 매계변수로 정의하고 this를 이용해 thisproduct Obj를 가리키도록 하였고 사용자가 입력한 제품명을 배열에 저장하기 위해 save method를 추가한다. save method는 들어오는 입력 값을 배열에 저장하고, fetchAll method는 배열에 저장된 모든 값들을 반환한다.

이제 모델을 통해 들어오는 data를 저장하고 객체를 생성하기 위해 controller를 수정한다.

//controllers/products.js

//const products = [];//model에 이미 정의 했기 때문에 더이상 controller에서 필요가 없어짐 
const Product = require('../models/product')//import class Product

exports.postAddProduct = (req, res, next) => {
	//products.push({ title: req.body.title });//model에 이미 정의 했기 때문에 더이상 controller에서 필요가 없어짐 
	const product = new Product(req.body.title)//model에 정의한 class Product을 이용하여 객체를 생성함, keyword : new + class 
    product.save()//생성환 객체를 save method를 통해, 배열에 저장
    res.redirect("/");
}

exports.getProduct = (req, res, next) => {
    const products = Product.fetchAll();//저장된 배열내 data call
    res.render("shop", {
        prods: products,
        docTitle: "Shop",
        path: "/",
        hasProducts: products.length > 0,
        activeShop: true,
        productCSS: true,
        
	});
}

models에서 정의한 class를 require를 통해 불러오고 postAddProduct에서 new를 이용해 객체를 생성한다. 이때 req.body.title의 값이 constructor()의 매계변수로 전달되어 배열에 저장되어 진다. 배열에 저장될수 있는 이유는 postAddProduct에서 product.save()를 호출하기 때문이다. 그리고 getProductconst products = Product.fetchAll(); 저장된 배열의 모든 값을 해당 뷰를 렌더링시에 전달하여 화면에 출력한다.

profile
아악! 뜨거워!!

0개의 댓글