클래스와 객체가 서로
의존(Dependency)하고 있는 것!
//product.controller.js
import { CashService } from './services/cash.service.js'
import { ProductService } from './services/product.service.js'
export class ProductController{
buyProduct = (req, res) => {
// 1. 가진돈 검증하는 코드 (대략 10줄 => class로 인해 2줄)
const cashService = new CashService() //강한 결합
const hasMoney = cashService.checkValue()
// 2. 판매여부 검증하는 코드 (대략 10줄 => class로 인해 2줄)
const productService = new ProductService() // 강한 결합
const isSoldout = productService.checkSoldOut()
// 3. 상품 구매하는 코드
if(hasMoney && !isSoldout ){
res.send("상품 구매 완료!!")
}
}
refundProduct = (req,res) => {
// 1. 판매여부 검증하는 코드 (대략 10줄 => class로 인해 2줄)
const productService = new ProductService() //강한 결합
const isSoldout = productService.checkSoldOut()
// 2. 상품 환불하는 코드
if(isSoldout){
res.send("상품 환불 완료!!")
}
}
}
ProductController 클래스에 선언한 메서드에서 CashService,ProductService 의 객체를 직접 생성해 메서드를 호출하는 형태 코드이다.
ProductController 클래스가 CashService, ProductService 클래스를 직접 사용해 생성한 객체에 의존하고 있는 강한 결합 상태이다.
⇒new 를 세번 사용해 메모리를 더 잡아먹는 단점이 생긴다.
⇒ ex) 여기서 CashService 가 CouponService 로 바뀌게 되면 다른 객체들의 변경이 요구되며 하나하나 바꿔줘야하는 단점이 생긴다.
ProductController가 CashService와 ProductService에 **의존성이 존재한다고 하는 것**이며,
다른 말로는 **강하게 결합되어 있다(Tight Coupling)**라고도 부른다.
// 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";
import { ProductService } from "./mvc/controllers/services/product.service.js";
const app = express();
// 추가되는 부분
const cashService = new CashService();
// 상품 API
const productController = new ProductController(cashService);
app.post("/products/buy", productController.buyProduct);
app.post("/products/refund", productController.refundProduct);
// 쿠폰(상품권) API
const couponController = new CouponController();
app.post("/coupons/buy", couponController.buyCoupon);
app.listen(3000, () => {
console.log("백엔드 API 서버가 켜졌어요!!!");
});
controller.js 에 있는 new Cashservice() 을 index.js 밖에서 실행시켜 준다.
ProductController 인자를 cashService 을 넣어줌으로써 cashService 를 생성자로 넣어주게 된다.
그리고 product.controller.js 파일에서 constructor(){} 함수를 추가해준다.
// product.controller.js
import { ProductService } from './services/product.service.js'
// import { CashService } from "./services/point.service.js";
export class ProductController {
//추가 코드 🐥
constructor(cashService) {
this.cashService = cashService;
}
buyProduct = (req, res) => {
// 1. 가진돈 검증하는 코드(10줄 => 2줄 => 1줄)
// const cashService = new CashService();
const hasMoney = this.cashService.checkValue();
// 판매여부 검증하는 코드(10줄 => 2줄)
const productService = new ProductService()
const isSoldout = productService.checkSoldout();
// 3. 상품 구매하는 코드
if (hasMoney && !isSoldout) {
res.send("상품을 구매합니다.");
}
};
refundProduct = (req, res) => {
// 1. 판매여부 검증하는 코드(10줄 => 2줄 => 1줄)
const productService = new ProductService()
const isSoldout = productService.checkSoldout();
// 2. 상품 환불하는 코드
if (isSoldout) {
res.send("상품을 환불합니다.");
}
};
}
그리곤 hasMoney 선언해준 코드에서 cashService 앞에 this.를 반드시 붙여줘야한다.
this.을 사용하게 되면 ProductController class 안의 함수들 선택이 가능해지게 됩니다!
이와 같은 결과로 보면,
ProductController 클래스는 CashService 클래스를 사용해 객체를 생성하지 않는다.
ProductController 외부에서 객체를 생성하여 constructor를 통해 안으로 전달하는 형태이다.
Constructor Injection(생성자 주입)을 사용하는 의존성 주입(Dependency Injection)으로 두 클래스를 느슨한 결합 상태로 만든 것이다.
✋ 주의점 .
의존성주입으로싱글톤 패턴을 구현가능하게 하지만의존성주입이싱글톤 패턴이 아니다.
객체의
인스턴스가 오직 1개만 생성되는 패턴이다.
인스턴스??비슷한 성질(?)을 가진 여러개의 객체를 만들기 위해서 생성자 함수,
Constructor를 만들어 찍어내듯이 사용하는데 이렇게 생성된 객체를 인스턴스라 부를 수 있습니다. 객체지향언어에서 흔히 사용되는 클래스(Class)가 자바스크립트에서는 프로토타입(prototype)이며 생성자 함수가 사용됩니다. 다시 말하면 클래스나 프로토타입을 사용하여 만들어 낸 것이인스턴스라고 볼 수 있습니다.