본 캠프 12일차 TIL

정희준·2023년 3월 29일
0
post-thumbnail

📌 오늘의 내용

Tight-coupling & Dependency

말 그대로 강한 결합이라는 뜻으로 클래스와 객체가 서로 의존 하고 있다는 뜻이며 느슨한 결합의 반대 개념이다!

예제 코드를 통해 알아보자

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("상품 환불 완료!!");
    }
  };
}

위 예제 코드를 살펴보면 ProductController라는 클래스가
CashService와 ProductService에의해 동작 되는 것을 볼수 있는데
이것을 ProductController가 CashService와ProductService에 의존하고 있다,강하게 결합되어있다(tight-coupling) 라고 볼 수 있다


강한 결합(Tight Coupling)의 특징

  • 하나의 객체를 변경하게 되면 다른 객체들을 변경을 요구되어 변경점들을 확인하고 쉽게 놓칠 수 있습니다.
  • 결합이 강하게 되어있어 결합이 되어있지 않으면 사용을 할 수 없게 됩니다.
  • new를 선언할 때마다 컴퓨터 메모리를 사용하게 되는데 비교적으로 강한 결합에서 new를 더 많이 사용해 메모리를 많이 잡아먹게 됩니다.

Loose-coupling & Dependency

위에서 살펴본 강한 결합의 반대적 개념으로
느슨한 결합(Loose Coupling)이란 "객체들 간에 결합이 되어있긴 하는데 헐겁게 됐다."로 해석할 수 있으며,

다른 클래스를 직접적으로 사용하는 클래스의 의존성을 줄이는 것입니다.

예제 코드를 통해 알아보자!

// 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 { CashService } from "./mvc/controllers/services/cash.service.js";
import { ProductService } from "./mvc/controllers/services/product.service.js";
import { PointService } from "./mvc/controllers/services/point.service .js";
const app = express(); // express에 있는 기능을 app에 담아줌 - > api만드는 기능 생성

const cashService = new CashService()                   
const productService = new ProductService()             
const pointService = new PointService()    

// 상품 API
const productController =  new ProductController(pointService, productService) // 느슨한 결합 loose-coupling
app.post("/products/buy", productController.buyProduct); // 상품 구매하기 API
app.post("/products/refund", productController.refundProduct); // 상품 환불하기 API

// 쿠폰(상품권) API
const couponController = new CouponController(cashService)
app.post("/coupons/buy", couponController.buyCoupon)

// 게시판 API
// app.get("/boards/...")

app.listen(3000); // 리슨 기다린다 (포트번호)

위 코드를 살펴보면 강한 결합이 되어있던 CashService와 ProductService를 객체로 선언 후 ProductController에 생성자 주입을 통해 전달인자로 넣어준것을 확인 할 수 있다

즉, 의존성 주입을 해주었다고 볼 수 있다

=== 의존성 주입으로 발생하는 장점! ===
1. new 한 번으로 모든 곳에서 재사용 가능 -> 싱글톤 패턴
2. 컨트롤러 코드를 수정하지 않고, 한꺼번에 변경 가능
3. 현금으로 결제하던 것을 포인트로 변경 가능

[부가설명]
1. ProductController가 CashService에 의존하고 있음(의존성 : CashService)
 => 이 상황을 "강하게 결합되어있다" 라고 표현
 => tight-coupling

2. 이를 개선하기 위해서 "느슨한 결합"으로 변경할 필요가 있음
 => loose-coupling
 => (의존성: CashService)을 밖에서 집어 넣어 주기
 => 이를 "의존성 주입"이라고 함
 => 영어로는 "Dependency-Injection", 줄여서 DI
 => 이 역할을 대신 해주는 Nestjs 기능 : IoC 컨테이너 (알아서 new 해서 넣어줌 즉, DI 해줌)
                                 => 영어로는 "Inversion-Of-Control"

3. "의존성주입"으로 "싱글톤패턴" 구현 가능해짐
 => Q) "의존성주입"이면, "싱글톤패턴"인가?
 => A) 그건 아님!

느슨한 결합(Loose Coupling)의 특징

  • 클래스/클래스를 느슨하게 결합되어 새로운 기능을 개발하거나 기존 기능을 수정하고 확장하는게 쉽습니다.
  • 코드의 유지 보수가 쉽습니다.
  • 테스트 대역으로 치환하기가 쉬워 유닛 테스트가 용이합니다.

TypeScript 사용 이유 및 사용방법

타입스크립트는 자바스크립트에 타입을 부여한 언어입니다.
자바스크립트의 확장된 언어라고 볼 수 있습니다.
타입스크립트는 자바스크립트와 달리 브라우저에서 실행하려면 파일을 한번 변환해 주어야 합니다.
이 변환 과정을 우리는 컴파일(complile) 이라고 부릅니다.

Why TypeScript?

타입스크립트는 아래 2가지 관점에서 자바스크립트 코드의 품질과 개발 생산성을 높일 수 있습니다.

  • 에러의 사전 방지
  • 코드 가이드 및 자동 완성(개발 생산성 향상)

TypeScript Basic 실습

// 타입추론 let str : string = "안녕하세요" :string 생략해도 처음 할당된 값에 의해 타입추론을 함
let str = "안녕하세요"
// str = 3 숫자타입 할당 불가

// 타입명시
let str2: string = "반갑습니다"

// 타입명시가 필요한 상황 number string 둘다 사용가능
let numStr: number | string = 1000
numStr = "1000원"

// 숫자타입
let num: number = 10

// 불린타입
let bool: boolean = true
bool = false
// bool = "false" 불가능

// 배열타입
let fff: number[] = [1, 2, 3, 4, 5]
let ggg: string[] = ["철수", "영희" , "훈이"]
let hhh: (string | number)[] = ["철수", "영희", 10] // 타입을 추론해서 어떤타입을 사용하는지 알아보기!


// 객체타입
const profile = {
    name : "철수",
    age : 8,
    school : "다람쥐초등학교"
}

profile.name = "훈이" // 타입 추론으로는 이것만 가능
// profile.age = "8살" number타입이기때문에 string 불가 
// profile.hobby = "수영" 타입 추론시 hobby 존재하지 않기 때문에 불가능

interface IProfile {
    name : string,
    age : number | string,
    school: string,
    hobby: string
}

// const profile2: IProfile = { hobby 속성이 없어서 에러
//     name : "철수",
//     age : 8,
//     school : "다람쥐초등학교"
// }

interface IProfile2 {
    name : string,
    age : number | string,
    school: string,
    hobby?: string
}

const profile2: IProfile2 = { // ? 사용하여 hobby없어도 가능
    name : "철수",
    age : 8,
    school : "다람쥐초등학교"
}

// any 타입
let qqq: any = "철수"   // 자바스크립트와 동일
qqq = 123
qqq = true

// 함수타입 => 어디서 누가 어떻게 호출할지 모르므로, 타입추론 할 수 없음(반드시, 타입명시 필요!!)
function add(num1: number, num2: number, unit: string): string {
    return num1 + num2 + unit
}

const result = add(1000,2000, "원") // 결과의 리턴 타입도 예측 가능!!

const add2 = (num1: number, num2: number, unit: string): string  => {
    return num1 + num2 + unit
}

const result2 = add2(1000,2000, "원") // 결과의 리턴 타입도 예측 가능!!

Decorator

데코레이터는 실행하려는 사용자가 구조를 수정하지 않고 기존 객체에 새로운 기능을 추가할 수 있도록 하는 디자인 패턴입니다.

일반적으로 데코레이트 하려는 함수의 정의 전에 호출됩니다. 데코레이터는 함수를 인수로 얻고 대가로 새로운 함수로 돌려주는 cllable(전달받은 object 인자가 호출 가능한지를 판단)구조 입니다.

자바스크립트를 확장한 언어라고 할 수 있는 타입 스크립트에서는 실험적인 기능으로 데코레이터를 제공하고 있습니다. 따라서 커맨드 라인이나 tsconfig.json에서 experimentalDecorators 옵션을 추가해 줘야 합니다.

데코레이터는 앞에서 말한 것처럼 “클래스”, “메서드”, “접근자”, “프로퍼티”, “파라미터”에 적용할 수 있습니다.

간단한 예제 코드 실습

function Controller(test: any) {
    console.log("==============")
    console.log(test)
    console.log("==============")
}


// 데코레이터 ->  함수의 전달인자로 클래스를 전달해줌
@Controller
class CatsController {

}


public / private / protected 와 readonly

작동 원리를 알아보기 위해 예제코드를 작성하여 확인해 보자!

public

class Monster2 {
  // power;       => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  constructor(public power) {
    // this.power = power => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  }


  attack1 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!");   // 내부에서 접근 가능
    this.power = 30 // 내부에서 변경 가능
  };

}

class miniMonster2 extends Monster2 {
  attack2 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!"); // 자식이 접근 가능
    this.power = 30 // 자식이 수정 가능
  };

}


const myMonster22 = new miniMonster2(20)
myMonster22.attack1()
myMonster22.attack2()
console.log(myMonster22.power)  // 외부에서 접근 가능
myMonster22.power = 50  // 외부에서 수정 가능

private

class Monster2 {
  // power;       => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  constructor(private power) {
    // this.power = power => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  }


  attack1 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!");   // 내부에서 접근 가능
    this.power = 30 // 내부에서 변경 가능
  };

}

class miniMonster2 extends Monster2 {
  attack2 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!"); // 자식이 접근 불가
    this.power = 30 // 자식이 수정 불가
  };

}


const myMonster22 = new miniMonster2(20)
myMonster22.attack1()
myMonster22.attack2()
console.log(myMonster22.power)  // 외부에서 접근 불가
myMonster22.power = 50  // 외부에서 수정 불가

protected

class Monster2 {
  // power;       => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  constructor(protected power) {
    // this.power = power => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  }


  attack1 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!");   // 내부에서 접근 가능
    this.power = 30 // 내부에서 변경 가능
  };

}

class miniMonster2 extends Monster2 {
  attack2 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!"); // 자식이 접근 가능
    this.power = 30 // 자식이 수정 가능
  };

}


const myMonster22 = new miniMonster2(20)
myMonster22.attack1()
myMonster22.attack2()
console.log(myMonster22.power)  // 외부에서 접근 불가
myMonster22.power = 50  // 외부에서 수정 불가

readonly

class Monster2 {
  // power;       => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  constructor(readonly power) {
    // this.power = power => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  }


  attack1 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!");   // 내부에서 접근 가능
    this.power = 30 // 내부에서 변경 불가
  };

}

class miniMonster2 extends Monster2 {
  attack2 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!"); // 자식이 접근 가능
    this.power = 30 // 자식이 수정 불가
  };

}


const myMonster22 = new miniMonster2(20)
myMonster22.attack1()
myMonster22.attack2()
console.log(myMonster22.power)  // 외부에서 접근 가능
myMonster22.power = 50  // 외부에서 수정 불가

private readonly

class Monster2 {
  // power;       => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  constructor(private readonly power) {
    // this.power = power => public, private, protected, readonly 중 1개라도 있으면 생략 가능
  }


  attack1 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!");   // 내부에서 접근 가능
    this.power = 30 // 내부에서 변경 불가
  };

}

class miniMonster2 extends Monster2 {
  attack2 = () => {
    console.log("공격하자!!");
    console.log("내 공격력은 " + this.power + "야!!!"); // 자식이 접근 불가
    this.power = 30 // 자식이 수정 불가
  };

}


const myMonster22 = new miniMonster2(20)
myMonster22.attack1()
myMonster22.attack2()
console.log(myMonster22.power)  // 외부에서 접근 불가
myMonster22.power = 50  // 외부에서 수정 불가

총 정리!

public 			 => 접근,수정 어디서든지 가능
private 		 => 내부에서만 접근,수정 가능
protected 		 => 내부,자식만 접근,수정 가능
readonly		 => 접근만 어디서든지 가능
private readonly => 내부에서 접근만 가능!

하루를 마치며 :)

오늘의 내용들은 next.js를 배우기 전 알아두면 좋은 이론들을 배워봤다
자바스크립트에서 false,'false' 이 데이터 타입 차이로 로직이 망가져 본적이 있는데 타입스크립트는 사전에 방지 할 수 있어 아주 좋은 것 같다! 내일 배울 nest.js를 이해하기 쉽게 오늘의 내용을 한번 더 복습하자~~🔥🔥🔥

profile
같이 일하고 싶은 사람이 되어보자! 다시 시작하는 개발 블로그.

0개의 댓글