์ปคํผ๋จธ์ ํด๋์ค๊ฐ ๋ค์๊ณผ ๊ฐ์ด ์๋ค.
type CoffeeCup = {
orderShot: number;
hasMilk: boolean;
};
interface CoffeeMaker {
makeCoffee(shots: number): CoffeeCup;
}
//์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ํด๋์ค์ด๋ค.
class CoffeMachine implements CoffeeMaker {
private static ONE_SHOT_CAPSULE: number = 3;
private static ONE_CUP_WATER: number = 10;
static makeMachine(beans: number, water: number): CoffeMachine {
return new CoffeMachine(beans, water);
}
constructor(private capsule: number = 3, private water: number = 10) {}
makeCoffee(orderShot: number): CoffeeCup {
this.checkMaterials(orderShot);
console.log("์บก์์ฐ๊ธฐ ์ " + this.capsule);
this.useCapsule(orderShot);
console.log("๋ฌผ์ฐ๊ธฐ ์ " + this.water);
this.useWater();
this.heatWater();
return this.extract(orderShot);
}
private checkMaterials(orderShot: number) {
if (this.capsule < orderShot * CoffeMachine.ONE_SHOT_CAPSULE) {
throw new Error(`์ปคํผ์บก์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์บก์ : ${this.capsule}`);
}
if (this.water < CoffeMachine.ONE_CUP_WATER) {
throw new Error(`๋ฌผ ๋ถ์กฑ!!! ๋จ์ ๋ฌผ ${this.water}`);
}
}
clean(): void {
console.log("์ปคํผ๋จธ์ ํ๊ตฌ๋ ์ค!");
}
private extract(shots: number): CoffeeCup {
return {
orderShot: shots,
hasMilk: false,
};
}
private heatWater() {
console.log("๋ฌผ ๋์ด๋ ์ค...");
}
private useCapsule(shot: number) {
console.log("์บก์์ฐ๋ฌ์์ต๋๋ค.");
this.capsule -= shot * CoffeMachine.ONE_SHOT_CAPSULE;
console.log("์บก์ ์ฐ๊ณ ๋ ํ" + this.capsule);
}
private useWater() {
console.log("๋ฌผ์ฐ๋ฌ์์ต๋๋ค.");
this.water -= CoffeMachine.ONE_CUP_WATER;
console.log("๋ฌผ์ฐ๊ณ ๋ ํ " + this.water);
}
addCapsule(capsule: number) {
this.capsule += capsule;
}
fulfillWater(water: number) {
this.water += water;
}
get Water(): number {
return this.water;
}
get Capsule(): number {
return this.capsule;
}
}
์นดํ๋ผํ ๋จธ์ ํด๋์ค๋ ๋ง๋ค์ด์ค๋ค.
์ปคํผ๋จธ์ ํด๋์ค ๋ด์ฉ ์ญ์ฑ ๋ณต๋ถํด์ค ๋ค์์
//return this.extract(orderShot); ์ ์ฝ๋ ์ฃผ์์ฒ๋ฆฌ ํด์ฃผ๊ณ
return { ...coffee, hasMilk: true }; ์ ์ฝ๋๋ก ๋ณ๊ฒฝํด์ฃผ๊ณ
์คํํฑ ๋ณ์ ์์ ์๋ณ์๋ฅผ ์นดํ๋ผ๋ผ๋จธ์ ์ผ๋ก ์น ๋ค ๋ฐ๊ฟ์ฃผ๋ฉด
ex)
CoffeMachine.ONE_SHOT_CAPSULE ->
CafeLatteMachine.ONE_SHOT_CAPSULE
class CafeLatteMachine {
private static ONE_SHOT_CAPSULE: number = 3;
private static ONE_CUP_WATER: number = 10;
static makeMachine(beans: number, water: number): CoffeMachine {
return new CoffeMachine(beans, water);
}
constructor(private capsule: number = 3, private water: number = 10) {}
makeCoffee(orderShot: number): CoffeeCup {
this.checkMaterials(orderShot);
console.log("์บก์์ฐ๊ธฐ ์ " + this.capsule);
this.useCapsule(orderShot);
console.log("๋ฌผ์ฐ๊ธฐ ์ " + this.water);
this.useWater();
this.heatWater();
let coffee = this.extract(orderShot);
return { ...coffee, hasMilk: true };
//return this.extract(orderShot);
}
private checkMaterials(orderShot: number) {
if (this.capsule < orderShot * CafeLatteMachine.ONE_SHOT_CAPSULE) {
throw new Error(`์ปคํผ์บก์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์บก์ : ${this.capsule}`);
}
if (this.water < CafeLatteMachine.ONE_CUP_WATER) {
throw new Error(`๋ฌผ ๋ถ์กฑ!!! ๋จ์ ๋ฌผ ${this.water}`);
}
}
clean(): void {
console.log("์ปคํผ๋จธ์ ํ๊ตฌ๋ ์ค!");
}
private extract(shots: number): CoffeeCup {
return {
orderShot: shots,
hasMilk: false,
};
}
private heatWater() {
console.log("๋ฌผ ๋์ด๋ ์ค...");
}
private useCapsule(shot: number) {
console.log("์บก์์ฐ๋ฌ์์ต๋๋ค.");
this.capsule -= shot * CafeLatteMachine.ONE_SHOT_CAPSULE;
console.log("์บก์ ์ฐ๊ณ ๋ ํ" + this.capsule);
}
private useWater() {
console.log("๋ฌผ์ฐ๋ฌ์์ต๋๋ค.");
this.water -= CafeLatteMachine.ONE_CUP_WATER;
console.log("๋ฌผ์ฐ๊ณ ๋ ํ " + this.water);
}
addCapsule(capsule: number) {
this.capsule += capsule;
}
fulfillWater(water: number) {
this.water += water;
}
get Water(): number {
return this.water;
}
get Capsule(): number {
return this.capsule;
}
}
...
์ฝ๋๋ฅผ ๊ฐ์ด ๋ณด๋ฉด ์์ฒญ ๊ธธ๊ณ , ์ฝ๋ ์ค๋ณต๋ ์ฌํ๋ค(๋๋ฝ๋ค!)
// //์ปคํผ๋จธ์ ๋ง๋ค๊ธฐ
type CoffeeCup = {
orderShot: number;
hasMilk: boolean;
};
interface CoffeeMaker {
makeCoffee(shots: number): CoffeeCup;
}
//์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ํด๋์ค์ด๋ค.
class CoffeMachine implements CoffeeMaker {
private static ONE_SHOT_CAPSULE: number = 3;
private static ONE_CUP_WATER: number = 10;
static makeMachine(beans: number, water: number): CoffeMachine {
return new CoffeMachine(beans, water);
}
constructor(private capsule: number = 3, private water: number = 10) {}
makeCoffee(orderShot: number): CoffeeCup {
this.checkMaterials(orderShot);
console.log("์บก์์ฐ๊ธฐ ์ " + this.capsule);
this.useCapsule(orderShot);
console.log("๋ฌผ์ฐ๊ธฐ ์ " + this.water);
this.useWater();
this.heatWater();
return this.extract(orderShot);
}
private checkMaterials(orderShot: number) {
if (this.capsule < orderShot * CoffeMachine.ONE_SHOT_CAPSULE) {
throw new Error(`์ปคํผ์บก์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์บก์ : ${this.capsule}`);
}
if (this.water < CoffeMachine.ONE_CUP_WATER) {
throw new Error(`๋ฌผ ๋ถ์กฑ!!! ๋จ์ ๋ฌผ ${this.water}`);
}
}
clean(): void {
console.log("์ปคํผ๋จธ์ ํ๊ตฌ๋ ์ค!");
}
private extract(shots: number): CoffeeCup {
return {
orderShot: shots,
hasMilk: false,
};
}
private heatWater() {
console.log("๋ฌผ ๋์ด๋ ์ค...");
}
private useCapsule(shot: number) {
console.log("์บก์์ฐ๋ฌ์์ต๋๋ค.");
this.capsule -= shot * CoffeMachine.ONE_SHOT_CAPSULE;
console.log("์บก์ ์ฐ๊ณ ๋ ํ" + this.capsule);
}
private useWater() {
console.log("๋ฌผ์ฐ๋ฌ์์ต๋๋ค.");
this.water -= CoffeMachine.ONE_CUP_WATER;
console.log("๋ฌผ์ฐ๊ณ ๋ ํ " + this.water);
}
addCapsule(capsule: number) {
this.capsule += capsule;
}
fulfillWater(water: number) {
this.water += water;
}
get Water(): number {
return this.water;
}
get Capsule(): number {
return this.capsule;
}
}
const maker: CoffeMachine = CoffeMachine.makeMachine(32, 100);
//์๋ง์ถ์ด์ ํ๋ก๋ ๋์ผํ ์ปคํผ๋จธ์ ์ ๋ฐ์์์๋ ๋ถ๊ตฌํ๊ณ ,
//amateur๋ ํด๋์คAmateurUser๊ฐ ์ธ์๋ฅผ ๋ฐ์ ๋ CoffeeMaker ์ธํฐํ์ด์ค๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฐ์์ค๊ณ ,
//pro๋ ํด๋์คProBarista๊ฐ ์ธ์๋ฅผ ๋ฐ์ ๋ CommercialCoffeeMaker ์ํ ํจ์์๋ฃฐ ๊ธฐ์ค์ผ๋ก ๋ฐ์์ค๊ธฐ ๋๋ฌธ์,
//๊ฐ๊ฐ ์ธํฐํ์ด์ค์ ์ ์ฝ๋ ํญ๋ชฉ๋ค๋ง ์ธ ์ ์๊ฒ๋๋ค.(์์๊ฐ์ ๊ฐ์ฉ ๋ฒ์๊ฐ ๋ฌ๋ผ์ง!!!)
console.log("/* ์ฒซ๋ฒ์งธ ์ฃผ๋ฌธ */");
let normalMachine = new CoffeMachine(10, 10);
console.log(normalMachine.Water); //10
console.log(normalMachine.Capsule); //10
let order1 = normalMachine.makeCoffee(2);
console.log(order1); //{ orderShot: 2 }
console.log("๋ฌผ ์ํ" + normalMachine.Water); //0
console.log("์บก์ ์ํ" + normalMachine.Capsule); //4
console.log("/* ๋๋ฒ์งธ ์ฃผ๋ฌธ */");
normalMachine.fulfillWater(100);
let order2 = normalMachine.makeCoffee(1);
console.log(order2); //{ orderShot: 1 }
console.log("๋ฌผ ์ํ" + normalMachine.Water); //90
console.log("์บก์ ์ํ" + normalMachine.Capsule); //1
console.log("/* ์ธ๋ฒ์งธ ์ฃผ๋ฌธ */");
let order3 = normalMachine.makeCoffee(3);
console.log(order3); //Error: ์ปคํผ์บก์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์บก์ : 1
class CafeLatteMachine {
private static ONE_SHOT_CAPSULE: number = 3;
private static ONE_CUP_WATER: number = 10;
static makeMachine(beans: number, water: number): CoffeMachine {
return new CoffeMachine(beans, water);
}
constructor(private capsule: number = 3, private water: number = 10) {}
makeCoffee(orderShot: number): CoffeeCup {
this.checkMaterials(orderShot);
console.log("์บก์์ฐ๊ธฐ ์ " + this.capsule);
this.useCapsule(orderShot);
console.log("๋ฌผ์ฐ๊ธฐ ์ " + this.water);
this.useWater();
this.heatWater();
let coffee = this.extract(orderShot);
return { ...coffee, hasMilk: true };
//return this.extract(orderShot);
}
private checkMaterials(orderShot: number) {
if (this.capsule < orderShot * CafeLatteMachine.ONE_SHOT_CAPSULE) {
throw new Error(`์ปคํผ์บก์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์บก์ : ${this.capsule}`);
}
if (this.water < CafeLatteMachine.ONE_CUP_WATER) {
throw new Error(`๋ฌผ ๋ถ์กฑ!!! ๋จ์ ๋ฌผ ${this.water}`);
}
}
clean(): void {
console.log("์ปคํผ๋จธ์ ํ๊ตฌ๋ ์ค!");
}
private extract(shots: number): CoffeeCup {
return {
orderShot: shots,
hasMilk: false,
};
}
private heatWater() {
console.log("๋ฌผ ๋์ด๋ ์ค...");
}
private useCapsule(shot: number) {
console.log("์บก์์ฐ๋ฌ์์ต๋๋ค.");
this.capsule -= shot * CafeLatteMachine.ONE_SHOT_CAPSULE;
console.log("์บก์ ์ฐ๊ณ ๋ ํ" + this.capsule);
}
private useWater() {
console.log("๋ฌผ์ฐ๋ฌ์์ต๋๋ค.");
this.water -= CafeLatteMachine.ONE_CUP_WATER;
console.log("๋ฌผ์ฐ๊ณ ๋ ํ " + this.water);
}
addCapsule(capsule: number) {
this.capsule += capsule;
}
fulfillWater(water: number) {
this.water += water;
}
get Water(): number {
return this.water;
}
get Capsule(): number {
return this.capsule;
}
}
๋ฌธ์ ์ํฉ์ ๊ณ ์น๊ธฐ ์ํ ์ด์ ๋ถํฐ '์์'์ ๋ณธ๊ฒฉ์ ์ผ๋ก ๋์ ํด๋ณธ๋ค.
์์์ ํตํด ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ์ ๋์ฌ๋ณด์
ํด๋์ค ์์์ extends ํค์๋,
์ธํฐํ์ด์ค ์์์ implements ํค์๋๋ฅผ ์จ์ผํ๋ค.
class CafeLatteMachine extends CoffeMachine {}
1. ์นดํ๋ผ๋ผ๋จธ์ ์ ์ปคํผ๋จธ์ ์ ์์ํ๋ค.
2. ์ปคํผ๋จธ์ ์์ฑ์ ์์ public ํน์ protected ํค์๋ ๊ธฐ์ฌ
<์ผ๋จ๋ฝ๋ ์ฝ๋>
// //์ปคํผ๋จธ์ ๋ง๋ค๊ธฐ
type CoffeeCup = {
orderShot: number;
hasMilk: boolean;
};
interface CoffeeMaker {
makeCoffee(shots: number): CoffeeCup;
}
//์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ํด๋์ค์ด๋ค.
class CoffeMachine implements CoffeeMaker {
private static ONE_SHOT_CAPSULE: number = 3;
private static ONE_CUP_WATER: number = 10;
static makeMachine(beans: number, water: number): CoffeMachine {
return new CoffeMachine(beans, water);
}
public constructor(private capsule: number = 3, private water: number = 10) {}
makeCoffee(orderShot: number): CoffeeCup {
this.checkMaterials(orderShot);
console.log("์บก์์ฐ๊ธฐ ์ " + this.capsule);
this.useCapsule(orderShot);
console.log("๋ฌผ์ฐ๊ธฐ ์ " + this.water);
this.useWater();
this.heatWater();
return this.extract(orderShot);
}
private checkMaterials(orderShot: number) {
if (this.capsule < orderShot * CoffeMachine.ONE_SHOT_CAPSULE) {
throw new Error(`์ปคํผ์บก์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์บก์ : ${this.capsule}`);
}
if (this.water < CoffeMachine.ONE_CUP_WATER) {
throw new Error(`๋ฌผ ๋ถ์กฑ!!! ๋จ์ ๋ฌผ ${this.water}`);
}
}
clean(): void {
console.log("์ปคํผ๋จธ์ ํ๊ตฌ๋ ์ค!");
}
private extract(shots: number): CoffeeCup {
return {
orderShot: shots,
hasMilk: false,
};
}
private heatWater() {
console.log("๋ฌผ ๋์ด๋ ์ค...");
}
private useCapsule(shot: number) {
console.log("์บก์์ฐ๋ฌ์์ต๋๋ค.");
this.capsule -= shot * CoffeMachine.ONE_SHOT_CAPSULE;
console.log("์บก์ ์ฐ๊ณ ๋ ํ" + this.capsule);
}
private useWater() {
console.log("๋ฌผ์ฐ๋ฌ์์ต๋๋ค.");
this.water -= CoffeMachine.ONE_CUP_WATER;
console.log("๋ฌผ์ฐ๊ณ ๋ ํ " + this.water);
}
addCapsule(capsule: number) {
this.capsule += capsule;
}
fulfillWater(water: number) {
this.water += water;
}
get Water(): number {
return this.water;
}
get Capsule(): number {
return this.capsule;
}
}
class CafeLatteMachine extends CoffeMachine {}
const machine = new CoffeMachine(100, 100);
const latteMachine = new CafeLatteMachine(100, 100);
const machine = new CoffeMachine(100, 100);
const latteMachine = new CafeLatteMachine(100, 100);
const latte = latteMachine.makeCoffee(10);
console.log(latte);
<์ถ๋ ฅ๊ฒฐ๊ณผ> //์ฐธ๊ณ ๋ก ๋ฌผ์ ์ท์ ์๊ด์์ด ํ์์ด๋ฉด ๋ฌด์กฐ๊ฑด -10(๋ด๊ฐ ๋ง๋ค์๋๋ฐ ์ ์ ํท๊ฐ...)
์บก์์ฐ๊ธฐ ์ 100
์บก์์ฐ๋ฌ์์ต๋๋ค.
์บก์ ์ฐ๊ณ ๋ ํ70
๋ฌผ์ฐ๊ธฐ ์ 100
๋ฌผ์ฐ๋ฌ์์ต๋๋ค.
๋ฌผ์ฐ๊ณ ๋ ํ 90
๋ฌผ ๋์ด๋ ์ค...
{ orderShot: 10, hasMilk: false } // ๋น์ฐํ ์์ง ๋ฐํฌ๋ ๋ค์ด๊ฐ์ง ์์ ๊ทธ๋ฅ ์ปคํผ๊ฐ ๋์๋ค~ ์ด์ ์ด๊ฑธ ๊ณ ์ณ์ฃผ์
์์ํด๋์ค์์ ๋ถ๋ชจํด๋์ค์ ์๋ ํจ์๋ฅผ ๋ฎ์ด์์ธ ์๊ฐ ์๋ค. ์ด๊ฒ์ด ๋ฐ๋ก ์ค๋ฒ๋ผ์ด๋ฉ(์ค๋ฒ๋ผ์ดํ )์ด๋ค.
class CafeLatteMachine extends CoffeMachine {
makeCoffee(orderShot: number): CoffeeCup {
this.checkMaterials(orderShot);
console.log("์บก์์ฐ๊ธฐ ์ " + this.capsule);
this.useCapsule(orderShot);
console.log("๋ฌผ์ฐ๊ธฐ ์ " + this.water);
this.useWater();
this.heatWater();
let latte = this.extract(orderShot);
return { ...latte, hasMilk: true };
}
}
์ผ๋จ์ ์์ ๊ฐ์ด ๋ณ๊ฒฝํ๋ฉด ๋ญ๊ฐ ์ด์ํ์ง ์์๊ฐ?
๋ ์ฝ๋์ค๋ณต์ด๋ค!
์ด๋ด ๋, super๋ผ๋ ๊ฒ์ ์ด์ฉํ๋ฉด ๋๋ค.
๋ถ๋ชจ์์ ๋ง๋ค์ด์ง ์ปคํผ์ ๋ฆฌํด๊ฐ์ธ ๊ฐ์ฒด์ hasMilk ํ๋กํผํฐ boolean๊ฐ๋ง ๋ฐ๊ฟ์ฃผ๊ธฐ ์ํ์ฌ ์๋์ ๊ฐ์ด ๋ณ๊ฒฝํด์ ์์ฑํด์ค๋ค.
class CafeLatteMachine extends CoffeMachine {
makeCoffee(orderShot: number): CoffeeCup {
const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์ ์๋น, ๋ฌผ ์๋น, ๋ฌผ ๊ฐ์ด ๋ค ๋๋๊ณ ์์ฑ๋ ์ปคํผ๊ฐ ๋ฐํ
//๋ถ๋ชจ์์ ๋ฐ์์จ ์ปคํผ ์์ฑํ์ ์ฐ์ ๋ง ๋ถ์ด์ฃผ์!!!
return { ...coffee, hasMilk: true };
}
}
const machine = new CoffeMachine(100, 100);
const latteMachine = new CafeLatteMachine(100, 100);
const latte = latteMachine.makeCoffee(10);
console.log(latte);
<์ถ๋ ฅ๊ฒฐ๊ณผ> ๊ณํ๋๋ก... ํ๋ฅญํ ์ถ๋ ฅ ๊ฒฐ๊ณผ
์บก์์ฐ๊ธฐ ์ 100
์บก์์ฐ๋ฌ์์ต๋๋ค.
์บก์ ์ฐ๊ณ ๋ ํ70
๋ฌผ์ฐ๊ธฐ ์ 100
๋ฌผ์ฐ๋ฌ์์ต๋๋ค.
๋ฌผ์ฐ๊ณ ๋ ํ 90
๋ฌผ ๋์ด๋ ์ค...
{ orderShot: 10, hasMilk: true }
ํ์ง๋ง ๋จ์ํ ํ๋กํผํฐ๋ฅผ ๋ณ๊ฒฝํ๋ ๊ฒ๋ณด๋ค๋
๊ฐ์ด๋Milk๋ฅผ ๋ฐ๋ก ๋ฃ์ด์ฃผ๋ ํจ์๋ฅผ ์นดํ๋ผ๋ผ ๋จธ์ ์ด ์ถ๊ฐํด์ฃผ๋ ๊ฒ์ด ๋ ๋ฉ์์ง ์์๊น?
์ถ๊ฐํ ๋ค, ์๋ ์ ์ฒด ์์ค์ฝ๋ ํ๋ฒ ๊ธฐ๋กํด๋ฃ๊ณ , ์ด์ด์ ์์ ํด๋ณด๋๋ก ํ๋ค.
<์ฌ๊ธฐ๊น์ง ์งํ๋ ์์ค์ฝ๋>
// //์ปคํผ๋จธ์ ๋ง๋ค๊ธฐ
type CoffeeCup = {
orderShot: number;
hasMilk: boolean;
};
interface CoffeeMaker {
makeCoffee(shots: number): CoffeeCup;
}
//์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ํด๋์ค์ด๋ค.
class CoffeMachine implements CoffeeMaker {
private static ONE_SHOT_CAPSULE: number = 3;
private static ONE_CUP_WATER: number = 10;
static makeMachine(beans: number, water: number): CoffeMachine {
return new CoffeMachine(beans, water);
}
public constructor(private capsule: number = 3, private water: number = 10) {}
makeCoffee(orderShot: number): CoffeeCup {
this.checkMaterials(orderShot);
console.log("์บก์์ฐ๊ธฐ ์ " + this.capsule);
this.useCapsule(orderShot);
console.log("๋ฌผ์ฐ๊ธฐ ์ " + this.water);
this.useWater();
this.heatWater();
return this.extract(orderShot);
}
private checkMaterials(orderShot: number) {
if (this.capsule < orderShot * CoffeMachine.ONE_SHOT_CAPSULE) {
throw new Error(`์ปคํผ์บก์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์บก์ : ${this.capsule}`);
}
if (this.water < CoffeMachine.ONE_CUP_WATER) {
throw new Error(`๋ฌผ ๋ถ์กฑ!!! ๋จ์ ๋ฌผ ${this.water}`);
}
}
clean(): void {
console.log("์ปคํผ๋จธ์ ํ๊ตฌ๋ ์ค!");
}
private extract(shots: number): CoffeeCup {
return {
orderShot: shots,
hasMilk: false,
};
}
private heatWater() {
console.log("๋ฌผ ๋์ด๋ ์ค...");
}
private useCapsule(shot: number) {
console.log("์บก์์ฐ๋ฌ์์ต๋๋ค.");
this.capsule -= shot * CoffeMachine.ONE_SHOT_CAPSULE;
console.log("์บก์ ์ฐ๊ณ ๋ ํ" + this.capsule);
}
private useWater() {
console.log("๋ฌผ์ฐ๋ฌ์์ต๋๋ค.");
this.water -= CoffeMachine.ONE_CUP_WATER;
console.log("๋ฌผ์ฐ๊ณ ๋ ํ " + this.water);
}
addCapsule(capsule: number) {
this.capsule += capsule;
}
fulfillWater(water: number) {
this.water += water;
}
get Water(): number {
return this.water;
}
get Capsule(): number {
return this.capsule;
}
}
// tslint:disable-next-line: max-classes-per-file
class CafeLatteMachine extends CoffeMachine {
makeCoffee(orderShot: number): CoffeeCup {
const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์ ์๋น, ๋ฌผ ์๋น, ๋ฌผ ๊ฐ์ด ๋ค ๋๋๊ณ ์์ฑ๋ ์ปคํผ๊ฐ ๋ฐํ
//๋ถ๋ชจ์์ ๋ฐ์์จ ์ปคํผ ์์ฑํ์ ์ฐ์ ๋ง ๋ถ์ด์ฃผ์!!!
this.steamMilk();
this.pourMilk();
return { ...coffee, hasMilk: true };
}
private steamMilk(): void {
console.log("์ฐ์ ๋ฐ์ฐ๋ ์ค...");
}
private pourMilk() {
console.log("์ฐ์ ๋ถ๋ ์ค...");
}
}
const machine = new CoffeMachine(100, 100);
const latteMachine = new CafeLatteMachine(100, 100);
const latte = latteMachine.makeCoffee(10);
console.log(latte);
<์ถ๋ ฅ ๊ฒฐ๊ณผ> //๋ถ๋ชจ์์ ํ ๋์๋ค์ ์ ๋ถ ๊ทธ๋๋ก ํ ๋ค์์, ์ฐ์ ๋ฐ์ฐ๊ณ , ์ฐ์ ๋ถ์ด์ hasMilk๊ฐ ture์ธ ์ง์ง ์นดํ๋ผ๋ผ๊ฐ ์์ฑ๋์๋ค!
์บก์์ฐ๊ธฐ ์ 100
์บก์์ฐ๋ฌ์์ต๋๋ค.
์บก์ ์ฐ๊ณ ๋ ํ70
๋ฌผ์ฐ๊ธฐ ์ 100
๋ฌผ์ฐ๋ฌ์์ต๋๋ค.
๋ฌผ์ฐ๊ณ ๋ ํ 90
๋ฌผ ๋์ด๋ ์ค...
์ฐ์ ๋ฐ์ฐ๋ ์ค...
์ฐ์ ๋ถ๋ ์ค...
{ orderShot: 10, hasMilk: true }
์... ๊ทธ๋ฐ๋ฐ ์ฌ๊ธฐ์ ์ฐ์ ๋ ์์ฑ์ ๋ํ์ฌ ์ฝ์ ๋ก๊ทธ๋ง ์ฐ์ง ๋ง๊ณ
์ค์ง์ ์ผ๋ก ์นดํ๋ผ๋ผ ๋จธ์ ์ ์ฐ์ ๋ฅผ ๋ด์ ์ ์์ด์, ์ฐ์ ๋ฅผ ์ฑ์๋ฃ๊ณ , ์ฐ์ ๊ฐ ๋ถ์กฑํ๋ฉด ์๋ฌ๋ฅผ ๋์ง๊ฒ๋...
ํ๋ง๋๋ก ๋์ฑ ์ด์์๋ ์์ํด๋์ค๋ก ๋ฐ๊ฟ ์ ์์๊น?
์๋ํด๋ณด์.
<์ต์ข ์์ค์ฝ๋> : ์์ฑ์ ์ค๋ฒ๋ผ์ด๋ฉ ๋ฐ ์ฌ๋ฌ๊ฐ์ง ํจ์ ์ค๋ฒ๋ผ์ด๋ฉ ์งํ!
// //์ปคํผ๋จธ์ ๋ง๋ค๊ธฐ
type CoffeeCup = {
orderShot: number;
hasMilk: boolean;
};
interface CoffeeMaker {
makeCoffee(shots: number): CoffeeCup;
}
//์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ํด๋์ค์ด๋ค.
class CoffeMachine implements CoffeeMaker {
private static ONE_SHOT_CAPSULE: number = 3;
private static ONE_CUP_WATER: number = 10;
static makeMachine(beans: number, water: number): CoffeMachine {
return new CoffeMachine(beans, water);
}
public constructor(
protected capsule: number = 3,
protected water: number = 10
) {}
makeCoffee(orderShot: number): CoffeeCup {
this.checkMaterials(orderShot);
console.log("์บก์์ฐ๊ธฐ ์ " + this.capsule);
this.useCapsule(orderShot);
console.log("๋ฌผ์ฐ๊ธฐ ์ " + this.water);
this.useWater();
this.heatWater();
return this.extract(orderShot);
}
protected checkMaterials(orderShot: number) {
if (this.capsule < orderShot * CoffeMachine.ONE_SHOT_CAPSULE) {
throw new Error(`์ปคํผ์บก์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์บก์ : ${this.capsule}`);
}
if (this.water < CoffeMachine.ONE_CUP_WATER) {
throw new Error(`๋ฌผ ๋ถ์กฑ!!! ๋จ์ ๋ฌผ ${this.water}`);
}
}
clean(): void {
console.log("์ปคํผ๋จธ์ ํ๊ตฌ๋ ์ค!");
}
private extract(shots: number): CoffeeCup {
return {
orderShot: shots,
hasMilk: false,
};
}
private heatWater() {
console.log("๋ฌผ ๋์ด๋ ์ค...");
}
private useCapsule(shot: number) {
console.log("์บก์์ฐ๋ฌ์์ต๋๋ค.");
this.capsule -= shot * CoffeMachine.ONE_SHOT_CAPSULE;
console.log("์บก์ ์ฐ๊ณ ๋ ํ" + this.capsule);
}
private useWater() {
console.log("๋ฌผ์ฐ๋ฌ์์ต๋๋ค.");
this.water -= CoffeMachine.ONE_CUP_WATER;
console.log("๋ฌผ์ฐ๊ณ ๋ ํ " + this.water);
}
addCapsule(capsule: number) {
this.capsule += capsule;
}
fulfillWater(water: number) {
this.water += water;
}
get Water(): number {
return this.water;
}
get Capsule(): number {
return this.capsule;
}
}
// tslint:disable-next-line: max-classes-per-file
class CafeLatteMachine extends CoffeMachine {
private static ONE_CUP_Milk: number = 2;
public constructor(
protected capsule: number = 3,
protected water: number = 10,
private milk: number
) {
super(capsule, water);
}
makeCoffee(orderShot: number): CoffeeCup {
const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์ ์๋น, ๋ฌผ ์๋น, ๋ฌผ ๊ฐ์ด ๋ค ๋๋๊ณ ์์ฑ๋ ์ปคํผ๊ฐ ๋ฐํ
//๋ถ๋ชจ์์ ๋ฐ์์จ ์ปคํผ ์์ฑํ์ ์ฐ์ ๋ง ๋ถ์ด์ฃผ์!!!
this.steamMilk();
this.pourMilk();
return { ...coffee, hasMilk: true };
}
//์ค๋ฒ๋ผ์ด๋ฉ
checkMaterials(orderShot: number) {
super.checkMaterials(orderShot);
if (this.milk < CafeLatteMachine.ONE_CUP_Milk) {
throw new Error(`์ฐ์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์ฐ์ ๋ : ${this.milk}`);
}
}
private steamMilk(): void {
console.log("์ฐ์ ๋ฐ์ฐ๋ ์ค...");
}
private pourMilk() {
console.log("์ฐ์ ๋ถ๋ ์ค...");
this.milk -= CafeLatteMachine.ONE_CUP_Milk;
console.log("์ฐ์ ๋ถ๊ณ ๋ ๋ค " + this.milk);
}
public fulfillMilk(milk: number) {
this.milk += milk;
}
get Milk(): number {
return this.milk;
}
}
const machine = new CoffeMachine(100, 100);
const latteMachine = new CafeLatteMachine(100, 100, 2);
const latte1 = latteMachine.makeCoffee(10);
console.log("์ฒซ๋ฒ์งธ ๋ผ๋ผ...๋๊ตฌ๋๊ตฌ๋๊ตฌ...");
console.log(latte1);
console.log("์ง๊ธ ์ฐ์ ์ํ๋? : " + latteMachine.Milk);
console.log("์ฐ์ ๊ฐ ์์ผ๋๊น ์ถฉ์ ํด์ฃผ์");
latteMachine.fulfillMilk(2);
const latte2 = latteMachine.makeCoffee(10);
console.log("๋๋ฒ์งธ ๋ผ๋ผ~~~");
console.log(latte2);
const latte3 = latteMachine.makeCoffee(10);
console.log("์ฐ์ ๊ฐ ์๋ ์ํ์์ ์ธ๋ฒ์งธ ๋ผ๋ผ๋ฅผ ๋ง๋ค๋ ค๊ณ ํ๋ฉด~~?");
console.log(latte3);
<์ถ๋ ฅ๊ฒฐ๊ณผ>
์บก์์ฐ๊ธฐ ์ 100
์บก์์ฐ๋ฌ์์ต๋๋ค.
์บก์ ์ฐ๊ณ ๋ ํ70
๋ฌผ์ฐ๊ธฐ ์ 100
๋ฌผ์ฐ๋ฌ์์ต๋๋ค.
๋ฌผ์ฐ๊ณ ๋ ํ 90
๋ฌผ ๋์ด๋ ์ค...
์ฐ์ ๋ฐ์ฐ๋ ์ค...
์ฐ์ ๋ถ๋ ์ค...
์ฐ์ ๋ถ๊ณ ๋ ๋ค 0
์ฒซ๋ฒ์งธ ๋ผ๋ผ...๋๊ตฌ๋๊ตฌ๋๊ตฌ...
{ orderShot: 10, hasMilk: true }
์ง๊ธ ์ฐ์ ์ํ๋? : 0
์ฐ์ ๊ฐ ์์ผ๋๊น ์ถฉ์ ํด์ฃผ์
์บก์์ฐ๊ธฐ ์ 70
์บก์์ฐ๋ฌ์์ต๋๋ค.
์บก์ ์ฐ๊ณ ๋ ํ40
๋ฌผ์ฐ๊ธฐ ์ 90
๋ฌผ์ฐ๋ฌ์์ต๋๋ค.
๋ฌผ์ฐ๊ณ ๋ ํ 80
๋ฌผ ๋์ด๋ ์ค...
์ฐ์ ๋ฐ์ฐ๋ ์ค...
์ฐ์ ๋ถ๋ ์ค...
์ฐ์ ๋ถ๊ณ ๋ ๋ค 0
๋๋ฒ์งธ ๋ผ๋ผ~~~
{ orderShot: 10, hasMilk: true }
/Users/๊ฒฝ๋ก/Desktop/๊ฒฝ๋ก/dist/index.js
throw new Error(`์ฐ์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์ฐ์ ๋ : ${this.milk}`);
^
Error: ์ฐ์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์ฐ์ ๋ : 0
์ฑ๊ณต์ ์ด๋ค!!
์ด์ฒ๋ผ ์์์ ์ ์ด์ฉํ๋ฉด ๊ณตํต์ ์ธ ๊ธฐ๋ฅ์ ๊ทธ๋๋ก ์ฌ์ฌ์ฉํ๋ฉด์,
์์ํด๋์ค์์๋ง ์กฐ๊ธ ๋ ์์ํด๋์ค์ ํนํ๋ ๊ธฐ๋ฅ๋ค์ ํ ์ ์๊ณ , ์ถ๊ฐํ ์๋ ์๋ค.
๊ทธ๋ฆฌ๊ณ super๋ผ๋ ํค์๋๋ฅผ ์ด์ฉํด์ ๋ถ๋ชจ ํด๋์ค์ ์๋ ํจ์๋ค์ ํธ์ถํ๊ฑฐ๋ ์ ๊ทผํ ์๋ ์๋ค.
๋ค๋ง, ์์ฑ์ ์ค๋ฒ๋ผ์ด๋ฉ์ ์ฃผ์ํ ์ ์ด ํฌ๊ฒ 2๊ฐ ์๋ค.
๋ง์ฝ ์์ ํด๋์ค์์ ๋ ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฅผ ์์ฑ์์์ ๋ฐ๊ณ ์ถ๋ค๋ฉด (์์์์ constructor์ ๋ค๋ฅธ ๋งค๊ฐ๋ณ์๋ฅผ ์ถ๊ฐํด์ฃผ๋ ๋ฑ ๋ค๋ฅธ ์์ ์ ์ถ๊ฐํด์ฃผ๊ธฐ ์ํด์ ์์ ํด๋์ค ์์ฑ์๋ฅผ ์ํผ ํด๋์ค ์์ฑ์์ ๋ค๋ฅด๊ฒ ๋ฐ๋ก ๊ตฌํํ๊ณ ์ ํ ๊ฒฝ์ฐ์๋)
์์ํด๋์ค์์์ ์์ฑ์(derived classes)๋ ๊ผญ super์ ํธ์ถํด์ผ ํ๋ค.
์ฆ, ์ ์บก์ฒ์ฒ๋ผ ์์ฑ์๋ super() ํ์์ผ๋ก ๋ฌ์์ฃผ๊ณ , ์ธ์ ์ฑ์์ฃผ๋ ์์ผ๋ก ๋ถ๋ฌ์ฃผ๋ฉด ๋๋ค.
super(capsule, water)
๋ ํ๋ ์ ๋ ํ ์ ์ ์์ํด๋์ค ์์ ์ฐ๋ ์์ฑ์์์ super()๋ฅผ ํธ์ถํ ์ ์๋ค๋ ๊ฒ ์์ฒด๊ฐ ๋ถ๋ชจ์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฌผ๋ ค๋ฐ์ ์ค๊ณ๋๋ผ๋ ๋ป์ด๋ค! super()๊น์ง ์ด ๋ค์์ ๋ง์ฐ์ค๋ง ์ฌ์ฉ ์ฌ๋ฆฌ๋ฉด ์ด๋ค ์ธ์๋ฅผ ์ ๋ฌํด์ผ๋ง ํ๋์ง ๋ค ์๋ ค์ค๋ค(๊ตฟ)
๊ทธ๋ฌ๋ฏ๋ก ์์ ํด๋์ค ์์์ ์ฐ๋ ์์ฑ์ ์์ ์ต์ super๊ฐ ์๊ตฌํ๋ ๋งค๊ฐ๋ณ์๋ฅผ ์จ์ฃผ์ด์ผ๋ง ํ๋ค.
๊ทธ๋ ๊ฒ ์์ ํด๋์ค ์์ฑ์ ๋งค๊ฐ๋ณ์๋ค ์ค์์ ๋ถ๋ชจ ํด๋์ค์์ ํ์ํ ๋ฐ์ดํฐ๋ ๋ฐ์์ฃผ๊ณ ๋, ์ด๋ ๊ฒ ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ super(์ฌ๊ธฐ์์ ์ ๋ฌ์ ํด์ฃผ์ด์ผ ํ๋ค.)
์ฐธ๊ณ ๋ก ๋งค๊ฐ๋ณ์๋ก ํ๋ฒ ๋ฐ์์จ ์ธ์ ๊ฐ์ด ๋ฐ๋ ์ผ์ด ์๋ค๋ฉด
constructor(beans: number, public readonly serialNumber : string)
readonly๋ฅผ ๋ถ์ฌ ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ๋ฐ๊พธ์ด ์ค ์๋ ์๋ค.
class CafeLatteMachine extends CoffeMachine {
private static ONE_CUP_Milk: number = 2;
public constructor(
protected capsule: number = 3,
protected water: number = 10,
private milk: number,
public readonly serialNumber: string
) {
super(capsule, water);
}
//...
}
const latteMachine = new CafeLatteMachine(100, 100, 2, "1S");
console.log(latteMachine.serialNumber);
coolํ ์์ ๊ธฐ๋ฅ ์ ์ฉํด๋ณด๊ธฐ ์ค์ต ๋!
<์ต์ข ์ฝ๋์ ์ถ๋ ฅ ๊ฒฐ๊ณผ>
- ์ต์ข ์ฝ๋
// //์ปคํผ๋จธ์ ๋ง๋ค๊ธฐ
type CoffeeCup = {
orderShot: number;
hasMilk: boolean;
};
interface CoffeeMaker {
makeCoffee(shots: number): CoffeeCup;
}
//์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ํด๋์ค์ด๋ค.
class CoffeMachine implements CoffeeMaker {
private static ONE_SHOT_CAPSULE: number = 3;
protected static ONE_CUP_WATER: number = 10;
static makeMachine(beans: number, water: number): CoffeMachine {
return new CoffeMachine(beans, water);
}
public constructor(
protected capsule: number = 3,
protected water: number = 10
) {}
makeCoffee(orderShot: number): CoffeeCup {
this.checkMaterials(orderShot);
console.log("์บก์์ฐ๊ธฐ ์ " + this.capsule);
this.useCapsule(orderShot);
console.log("๋ฌผ์ฐ๊ธฐ ์ " + this.water);
this.useWater();
this.heatWater();
return this.extract(orderShot);
}
protected checkMaterials(orderShot: number) {
if (this.capsule < orderShot * CoffeMachine.ONE_SHOT_CAPSULE) {
throw new Error(`์ปคํผ์บก์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์บก์ : ${this.capsule}`);
}
if (this.water < CoffeMachine.ONE_CUP_WATER) {
throw new Error(`๋ฌผ ๋ถ์กฑ!!! ๋จ์ ๋ฌผ ${this.water}`);
}
}
clean(): void {
console.log("์ปคํผ๋จธ์ ํ๊ตฌ๋ ์ค!");
}
private extract(shots: number): CoffeeCup {
return {
orderShot: shots,
hasMilk: false,
};
}
private heatWater() {
console.log("๋ฌผ ๋์ด๋ ์ค...");
}
private useCapsule(shot: number) {
console.log("์บก์์ฐ๋ฌ์์ต๋๋ค.");
this.capsule -= shot * CoffeMachine.ONE_SHOT_CAPSULE;
console.log("์บก์ ์ฐ๊ณ ๋ ํ" + this.capsule);
}
protected useWater() {
console.log("๋ฌผ์ฐ๋ฌ์์ต๋๋ค.");
this.water -= CoffeMachine.ONE_CUP_WATER;
console.log("๋ฌผ์ฐ๊ณ ๋ ํ " + this.water);
}
addCapsule(capsule: number) {
this.capsule += capsule;
}
fulfillWater(water: number) {
this.water += water;
}
get Water(): number {
return this.water;
}
get Capsule(): number {
return this.capsule;
}
}
// tslint:disable-next-line: max-classes-per-file
class CafeLatteMachine extends CoffeMachine {
protected static ONE_CUP_WATER: number = 8;
private static ONE_CUP_Milk: number = 2;
public constructor(
protected capsule: number = 3,
protected water: number = 10,
private milk: number,
public readonly serialNumber: string
) {
super(capsule, water);
}
makeCoffee(orderShot: number): CoffeeCup {
const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์ ์๋น, ๋ฌผ ์๋น, ๋ฌผ ๊ฐ์ด ๋ค ๋๋๊ณ ์์ฑ๋ ์ปคํผ๊ฐ ๋ฐํ
//๋ถ๋ชจ์์ ๋ฐ์์จ ์ปคํผ ์์ฑํ์ ์ฐ์ ๋ง ๋ถ์ด์ฃผ์!!!
this.steamMilk();
this.pourMilk();
return { ...coffee, hasMilk: true };
}
//์ค๋ฒ๋ผ์ด๋ฉ
checkMaterials(orderShot: number) {
super.checkMaterials(orderShot);
if (this.milk < CafeLatteMachine.ONE_CUP_Milk) {
throw new Error(`์ฐ์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์ฐ์ ๋ : ${this.milk}`);
}
}
useWater() {
console.log("๋ฌผ์ฐ๋ฌ์์ต๋๋ค.");
this.water -= CafeLatteMachine.ONE_CUP_WATER;
console.log("๋ฌผ์ฐ๊ณ ๋ ํ " + this.water);
}
private steamMilk(): void {
console.log("์ฐ์ ๋ฐ์ฐ๋ ์ค...");
}
private pourMilk() {
console.log("์ฐ์ ๋ถ๋ ์ค...");
this.milk -= CafeLatteMachine.ONE_CUP_Milk;
console.log("์ฐ์ ๋ถ๊ณ ๋ ๋ค " + this.milk);
}
public fulfillMilk(milk: number) {
this.milk += milk;
}
get Milk(): number {
return this.milk;
}
}
const machine = new CoffeMachine(100, 100);
const latteMachine = new CafeLatteMachine(100, 100, 2, "1S");
const latte1 = latteMachine.makeCoffee(10);
console.log("์ฒซ๋ฒ์งธ ๋ผ๋ผ...๋๊ตฌ๋๊ตฌ๋๊ตฌ...");
console.log(latte1);
console.log("์ง๊ธ ์ฐ์ ์ํ๋? : " + latteMachine.Milk);
console.log("์ฐ์ ๊ฐ ์์ผ๋๊น ์ถฉ์ ํด์ฃผ์");
latteMachine.fulfillMilk(2);
const latte2 = latteMachine.makeCoffee(10);
console.log("๋๋ฒ์งธ ๋ผ๋ผ~~~");
console.log(latte2);
const latte3 = latteMachine.makeCoffee(10);
console.log("์ฐ์ ๊ฐ ์๋ ์ํ์์ ์ธ๋ฒ์งธ ๋ผ๋ผ๋ฅผ ๋ง๋ค๋ ค๊ณ ํ๋ฉด~~?");
console.log(latte3);
console.log(latteMachine.serialNumber);
- ์ถ๋ ฅ ๊ฒฐ๊ณผ
์บก์์ฐ๊ธฐ ์ 100
์บก์์ฐ๋ฌ์์ต๋๋ค.
์บก์ ์ฐ๊ณ ๋ ํ70
๋ฌผ์ฐ๊ธฐ ์ 100
๋ฌผ์ฐ๋ฌ์์ต๋๋ค.
๋ฌผ์ฐ๊ณ ๋ ํ 92
๋ฌผ ๋์ด๋ ์ค...
์ฐ์ ๋ฐ์ฐ๋ ์ค...
์ฐ์ ๋ถ๋ ์ค...
์ฐ์ ๋ถ๊ณ ๋ ๋ค 0
์ฒซ๋ฒ์งธ ๋ผ๋ผ...๋๊ตฌ๋๊ตฌ๋๊ตฌ...
{ orderShot: 10, hasMilk: true }
์ง๊ธ ์ฐ์ ์ํ๋? : 0
์ฐ์ ๊ฐ ์์ผ๋๊น ์ถฉ์ ํด์ฃผ์
์บก์์ฐ๊ธฐ ์ 70
์บก์์ฐ๋ฌ์์ต๋๋ค.
์บก์ ์ฐ๊ณ ๋ ํ40
๋ฌผ์ฐ๊ธฐ ์ 92
๋ฌผ์ฐ๋ฌ์์ต๋๋ค.
๋ฌผ์ฐ๊ณ ๋ ํ 84
๋ฌผ ๋์ด๋ ์ค...
์ฐ์ ๋ฐ์ฐ๋ ์ค...
์ฐ์ ๋ถ๋ ์ค...
์ฐ์ ๋ถ๊ณ ๋ ๋ค 0
๋๋ฒ์งธ ๋ผ๋ผ~~~
{ orderShot: 10, hasMilk: true }
/Users/๊ฒฝ๋ก๋ช
/Desktop/ํ๋ก์ ํธ๋ช
/dist/index.js:87
throw new Error(`์ฐ์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์ฐ์ ๋ : ${this.milk}`);
^
Error: ์ฐ์ ๋ถ์กฑ!!! ํ์ฌ ๋ณด์ ์ฐ์ ๋ : 0
Node.js v17.7.1