🌼 학습내용
1️⃣ 의존성 주입
의존성 주입이란 강한 결합을 느슨한 결합으로 만드는 DI(의존성 주입)이다. 
⛔️ 강한결합
강한 결합에서는 비교적 new를 더 많이 사용해 메모리를 많이 잡아먹게 된다. 
export class ProductController {
  buyProduct = (req, res) => {
    const cashService = new CashService();
    const hasMoney = cashService.checkValue();
    
    const productService = new ProductService();
    const isSoldout = productService.checkSoldout(); 
  };
  refundProduct = (req, res) => {
    const productService = new ProductService();
    const isSoldout = productService.checkSoldout(); 
  };
}
ProductController가 CashService와 ProductService에 의존하고 있는 상태 
하위클래스(CashService와ProductService)가 정의 되지 않으면 
상위클래스(ProductController)를 정의할 수 없다. 
하위클래스를 수정하게 되면 상위 클래스도 대부분에서 변경이 일어나게 된다. 
⛔️ 느슨한 결합(의존성 주입)
클래스/클래스를 느슨하게 결합되어 새로운 기능을 개발하거나 기존 기능을 수정하고 확장하는게 쉽습니다. 
유지 보수가 비교적 쉽다. 
const cashService = new CashService();
const productController = new ProductController(cashService);
app.post("/products/buy", productController.buyProduct);
app.post("/products/refund", productController.refundProduct);
const couponController = new CouponController();
app.post("/coupons/buy", couponController.buyCoupon);
cashService 생성자를 ProductController() 안에 넣어주게 된다. 
export class ProductController {
   constructor(cashService) {
    this.cashService = cashService;
  }
  buyProduct = (req, res) => {
    
    const hasMoney = this.cashService.checkValue(); 
    
    const productService = new ProductService();
    const isSoldout = productService.checkSoldout(); 
  };
  refundProduct = (req, res) => {
    const productService = new ProductService();
    const isSoldout = productService.checkSoldout(); 
}
constructor 사용해 cashService를 받는다. 
⛔️ 싱글톤 패턴
index.js에서 new 한 번으로 모든 곳에서 사용 가능하게 된다. 
의존성 주입이면 싱글톤 패턴이다!? 그건 아니다. 
const cashService1 = new CashService();
const cashService2 = new CashService();
cashService1 와 cashService2 로 만들고 똑같은 CashService를 서로 다른 곳에서 사용 => 의존성 주입 O 싱글톤 패턴 X  
2️⃣ Typescript
Typescript 전반적인 이해
let aaa = '안녕하세요';
aaa = 3; 
let bbb: string = '반갑습니다.';
bbb = 10;
let ccc: number | string = 1000;
ccc = '1000원'; 
let ddd: number = 10;
ddd = '철수'; 
let eee: boolean = true;
eee = false;
eee = 'false'; 
let fff: number[] = [1, 2, 3, 4, 5, 'hi']; 
let ggg: string[] = ['철수', '영희', '훈이', 10];  
let hhh: (number | string)[] = [1, 2, 3, 4, 'Hi'];
interface IProfile {
    name: string;
    age: number | string;
    school: string;
    hobby?: string;
}
const profile: IProfile = {
    name: '짱구',
    age: 4,
    school: '떡잎유치원',
};
profile.name = '유리'; 
profile.age = '8살'; 
profile.hobby = '수영'; 
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, '원'); 
let qqq: any = '철수'; 
qqq = 123;
qqq = true;
3️⃣ Decorator(@)
Decorator는 함수로써 호출한다. 
aaa => [class CatsController]를 암시한다. 
function Controller(aaa: any) {
    console.log('=========');
    console.log(aaa);
    console.log('=========');
}
@Controller
class CatsController {}
4️⃣ public, private, protected,  readonly
public, private, protected, readonly 중 1개라도 있으면 생략가능 
① public
class Monster {
    
    constructor(public power) {
        
    }
    attack1 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
class 공중몬스터2 extends Monster {
    attack2 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
const mymonster = new 공중몬스터(20);
mymonster.attack1();
mymonster.attack2();
console.log(mymonster22.power); 
mymonster.power = 10; 
② private
class Monster {
    
    constructor(private power) {
        
    }
    attack1 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
class 공중몬스터 extends Monster {
    attack2 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
const mymonster = new 공중몬스터(20);
mymonster.attack1();
mymonster.attack2();
console.log(mymonster.power); 
mymonster.power = 10; 
③ protected
class Monster {
    
    constructor(protected power) {
        
    }
    attack1 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
class 공중몬스터 extends Monster {
    attack2 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
const mymonster = new 공중몬스터(20);
mymonster.attack1();
mymonster.attack2();
console.log(mymonster.power); 
mymonster.power = 10; 
④ readonly
class Monster {
    
    constructor(readonly power) {
        
    }
    attack1 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
class 공중몬스터 extends Monster {
    attack2 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
const mymonster = new 공중몬스터(20);
mymonster.attack1();
mymonster.attack2();
console.log(mymonster.power); 
mymonster.power = 10; 
⓹ private-readonly
class Monster {
    
    constructor(private readonly power) {
        
    }
    attack1 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
class 공중몬스터 extends Monster {
    attack2 = () => {
        this.power = 30; 
        console.log(`${this.power} 만큼 공격한다`); 
    };
}
const mymonster = new 공중몬스터(20);
mymonster.attack1();
mymonster.attack2();
console.log(mymonster.power); 
mymonster.power = 10;