오늘은 class에 대한 개념과 상속,전략패턴 MVC 패턴에대해 배우고 간단한 예제를 통해 실습을 해보았다 오늘의 배운 내용에 대해 알아보자!
클래스(class)
는 객체 지향 프로그래밍에서 특정 객체를 생성하기 위해 변수와 메소드를 정의하는 일종의 틀로,
객체를 정의하기 위한 상태(멤버 변수)와 메서드(함수)로 구성됩니다.
즉, 클래스(class)란 물건 만드는 설명서라고 생각하면 이해가 편하다!
기본적인 클래스 문법을 사용한 예제를 만들어보자!
class Monster {
// this.power this 생략됨
power;
// 생성자 메소드 초기값 설정
constructor(power) {
this.power = power
}
// 화살표 함수 사용가능
attack = () => {
console.log("공격하자!!");
// 변수 사용시에는 this 붙여줘야함
console.log("내 공격력은 " + this.power + "야!!!");
};
run() {
console.log("도망가자!!");
}
}
const myMonster1 = new Monster(20);
myMonster1.attack();
myMonster1.run();
const myMonster2 = new Monster(50);
myMonster2.attack();
myMonster2.run();
Monster 라는 클래스를 만들고 power라는 멤버변수를 선언 후
생성자를 만들고 attack,run 메소드를 만들었다!
new 연산자를 통해 새로운 객체를 만들고 Monster 클래스 내부의 메소드를 호출하는 코드이다
this를 사용하여 클래스 내부에 존재하는 다른 메소드또는 변수를 사용할 수 있다!
방금까지는 초기값은 다르지만 같은 클래스(Monster)를 사용해서 객체(mymonster1, mymonster2)를 만들어 주었습니다.
이번에는 서로 다른 클래스를 사용하여 객체를 만들어 줄 것인데, 두 객체가 가지는 공통점과 차이점이 존재하는 객체를 만들어야 할 때는 어떻게 만들어야 되는지 알아보자
class Monster {
// this.power this 생략됨
power = 10;
// 생성자 메소드
constructor(power) {
this.power = power
}
// 화살표 함수 사용가능
attack = () => {
console.log("공격하자!!");
// 변수 사용시에는 this 붙여줘야함
console.log("내 공격력은 " + this.power + "야!!!");
};
run() {
console.log("도망가자!!");
}
}
class miniMonster extends Monster {
constructor(power) {
// 입력받은 power을 부모 Monster의 인자로 넘김
super(power)
}
// 오버라이딩(부모의 run을 덮어쓰기)
run() {
console.log("살금살금 도망가자!!");
}
}
class bossMonster extends Monster{
constructor(power) {
// 입력받은 power + 5 을 부모 Monster의 인자로 넘김
super(power + 5)
}
// 오버라이딩(부모의 run을 덮어쓰기)
run() {
console.log("도망에 실패했다");
}
}
위 코드 처럼 같은 기능들을 사용할때는 코드의 효율성을 높이기 위해 중복되는 코드들을 최소화 시켜주기 위해 상속을 사용한다!
이번에는 하나의 Monster를 만들어두고, 무슨 기능을 넣어주냐에 따라서 이 Monster들이 서로 다른 Monster가 되도록 만들어 보겠습니다.
class 공중부품 {
run() {
console.log("날라서 도망가자!!");
}
}
class 지상부품 {
run() {
console.log("뛰어서 도망가자!!");
}
}
class Monster {
// this.power this 생략됨
power = 10;
부품;
// 생성자 메소드
constructor(parm) {
this.부품 = parm
}
// 화살표 함수 사용가능
attack = () => {
console.log("공격하자!!");
// 변수 사용시에는 this 붙여줘야함
console.log("내 공격력은 " + this.power + "야!!!");
};
run() {
this.부품.run()
}
}
const myMonster1 = new Monster(new 공중부품())
myMonster1.attack();
myMonster1.run();
const myMonster2 = new Monster(new 지상부품());
myMonster2.attack();
myMonster2.run();
위 예제 코드처럼 Monster는 고정시켜 둔 채로, 안의 부품을 갈아 끼워줌으로 서로 다른 Monster를 만들 수 있습니다.
어떤 부품을 사용하는게 좋을지, 전략적으로 사용함에 있어 전략 패턴이라고 합니다.
MVC란 Model-View-Controller의 약자로 애플리케이션을 세 가지 역할로 구분한 개발 방법론입니다.
controllers
에서는 미들웨어 함수를 분리해서 관리해 줄 것입니다.
models
에서는 DB 생성을 관리해주는 곳으로 이전에 배운 Schema 정의를 해 준 폴더와 동일합니다.
view
에는 화면에 보여지는 파일들(html 파일)을 관리해주는 폴더입니다.
위의 그림처럼 사용자가 controller를 조작하면 controller는 model을 통해서 데이터를 가져오고
그 정보를 바탕으로 시각적인 표현을 담당하는 View를 제어해서 사용자에게 전달하게 됩니다.
위의 개념을 WEB에 적용 시!
사용자가 웹사이트에 접속 (Users)
Controller는 사용자가 요청한 웹페이지를 서비스하기 위해서 모델을 호출 (Manipulates)
Model은 데이터베이스나 파일과 같은 데이터 소스를 제어한 후 그 결과를 Return
Controller는 Model이 리턴한 결과를 View에 반영 (Updates)
데이터가 반영된 View는 사용자에게 보여짐 (Sees)
사용자가 보는 페이지, 데이터처리, 그리고 이 2가지를 중간에서 제어하는 컨트롤,
이 3가지로 구성되는 하나의 애플리케이션을 만들면 각각 맡은 바에만 집중을 할 수 있게 됩니다.
공장에서도 하나의 역할들만 담당을 해서 처리를 해서 효율적이게 됩니다. 프로그래밍에서도 마찬가지입니다.
서로 분리되어 각자의 역할에 집중해 개발한다면, 유지보수성, 애플리케이션의 확장성,
그리고 유연성이 증가하고, 중복코딩이라는 문제점 또한 사라지게 됩니다.
서비스 로직을 제외한 MVC 패턴을 적용한 api 예제를 만들어보자 !
index.js
// const express = require('express') // 옛날방식 => commonjs
import express from "express"; // 요즘방식 => module
import { ProductController } from "./mvc/controllers/product.controller.js";
import { CouponController } from "./mvc/controllers/coupon.controller.js";
const app = express(); // express에 있는 기능을 app에 담아줌 - > api만드는 기능 생성
// 상품 API
const productController = new ProductController()
app.post("/products/buy", productController.buyProduct); // 상품 구매하기 API
app.post("/products/refund", productController.refundProduct); // 상품 환불하기 API
// 쿠폰(상품권) API
const couponController = new CouponController()
app.post("/coupons/buy", couponController.buyCoupon)
// 게시판 API
// app.get("/boards/...")
app.listen(3000); // 리슨 기다린다 (포트번호)
CouPonController
import { CashService } from "./services/cash.service.js"
export class CouponController{
buyCoupon = (req, res) => {
console.log(req.body)
// 1. 가진돈 검증하는 코드 (대략 10줄 => 2줄 )
const cashService = new CashService()
const hasMoney = cashService.checkValue()
// 2. 상품권 구매하는 코드
if(hasMoney){
res.send("상품권 구매 완료!!")
}
}
}
ProductController
import { CashService } from "./services/cash.service.js";
import { ProductService } from "./services/product.service.js";
export class ProductController {
buyProduct = (req, res) => {
console.log(req.body)
// 1. 가진돈 검증하는 코드 (대략 10줄 정도 => 2줄)
const cashService = new CashService();
const hasMoney = cashService.checkValue();
// 2. 판매여부 검증하는 코드 (대략 10줄 정도 => 2줄)
const productService = new ProductService();
const isSoldOut = productService.checkSoldOut();
// 3. 상품 구매하는 코드
if (hasMoney && !isSoldOut) {
res.send("상품 구매 완료!!");
}
};
refundProduct = (req, res) => {
// 1. 판매여부 검증하는 코드 (대략 10줄 정도 => 2줄)
const productService = new ProductService();
const isSoldOut = productService.checkSoldOut();
// 2. 상품 환불하는 코드
if (isSoldOut) {
res.send("상품 환불 완료!!");
}
};
}
CashService
// 서비스 로직은 미구현
export class CashService {
checkValue = () => {
// 1. 가진돈 검증하는 코드 (대략 10줄 정도)
// ...
// ...
// ...
// ...
};
}
ProductSevice
// 서비스 로직은 미구현
export class ProductService {
checkSoldOut = () => {
// 1. 판매여부 검증하는 코드 (대략 10줄 정도)
// ...
// ...
// ...
// ...
};
}
rest-api를 사용했던 퍼사드 패턴과 살짝 유사하지만 훨씬 간결하고 구조가 명확한것을 볼 수 있다
nest.js를 배우기 전 구조를 알기 위해 기존의 배웠던 node.js의 구조와는 다른 class와 mvc 패턴을 배워보았다 예전에 배운적이 있던 Java와 구조가 흡사한 느낌이다! class가 객체지향 프로그래밍을 활용해서 그런 것 같다!