TypeScript/ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ TypeScript

[ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ] ๊ฐ์ฒด์ง€ํ–ฅ์˜ ๊ฝƒ composition(๋ถ€์ œ: ์ƒ์†์˜ ๋ฌธ์ œ์ )

Rainbow๐ŸŒˆCoder 2022. 4. 22. 19:03
728x90

 

 

 Favor Composition over inheritance 

 

"์ƒ์† ๋Œ€์‹ ์— ์ปดํฌ์ง€์…˜(๋œป: ๊ตฌ์„ฑ์š”์†Œ๋“ค, ๊ตฌ์„ฑ)์„ ๋” ์„ ํ˜ธํ•˜์„ธ์š”."

 

 

 

 

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ OOP์˜ ๊ฝƒ, composition์„ ๋‹ค๋ฃจ๊ธฐ ์ „์— ์ƒ์†์˜ ๋ฌธ์ œ์ ์— ๋Œ€ํ•ด์„œ ๋จผ์ € ์•Œ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

๋ฏธ๋ฆฌ ๋งํ•˜์ž๋ฉด, composition์€ ๋ณต์žกํ•˜๊ฒŒ ์ƒ์†์˜ ์ˆ˜์ง ๊ตฌ์กฐ๊ฐ€ ๊ธธ์–ด์ง€๋Š” ๋Œ€์‹ ์— ์ƒ์†์˜ ๋ ˆ๋ฒจ์„ ํ•œ ๋‹จ๊ณ„๋กœ๋งŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๊ธฐ๋ฒ•์ด๋‹ค.

๋ฌธ์ œ์ ๋„ ๋ฏธ๋ฆฌ ๋งํ•˜์ž๋ฉด, composition์šฉ์œผ๋กœ ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ํด๋ž˜์Šค์™€ ๊ฐ€์ ธ์˜ค๋Š” ํด๋ž˜์Šค ์‚ฌ์ด์˜ ์ปคํ”Œ๋ง์ด ๋„ˆ๋ฌด ์‹ฌํ•˜๋‹ค๋Š” ์ ์ด ์žˆ๋‹ค.( ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ํด๋ž˜์Šค๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋กœ ๋ฐ”๊พธ๊ณ  ์‹ถ๋‹ค๋ฉด, ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ํด๋ž˜์Šค์™€ ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ํด๋ž˜์Šค์— ๋“ค์–ด๊ฐ€์„œ ์ฝ”๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•œ๋‹ค.-> ๋” ํ™•์žฅ์ด ์‰ฝ๊ณ  ์œ ์—ฐํ•œ ํ…Œํฌ๋‹‰์€ ๋‹ค์Œ ํฌ์ŠคํŒ…์„ ๋ณด๋ฉด๋œ๋‹ค(๊ฐ•๋ ฅํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด์šฉํ•œ ์ „๋žตํŒจํ„ด))

 

<์ƒ์†์˜ ๋ฌธ์ œ์ >

์กฑ๋ณด๊ฐ€ ๊ผฌ์ธ๋‹ค...

์ƒ์†์˜ ๊นŠ์ด๊ฐ€ ๋„ˆ๋ฌด ๊นŠ์–ด์ ธ์„œ ์กฐ์ง๋„๊ฐ€ ์ปค์ง€๋‹ค๋ณด๋ฉด ๊ด€๊ณ„์„ฑ์ด ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

 

 

์ปคํ”ผ๋จธ์‹ ์„ ์ƒ์†๋ฐ›์€ ์นดํŽ˜๋ผ๋–ผ๋จธ์‹ ๊ณผ ์†Œ๊ธˆ์ปคํ”ผ๋จธ์‹ ์ด ์žˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์†Œ๊ธˆ์นดํŽ˜๋ผ๋–ผ๋จธ์‹ ์ด ํ•„์š”ํ•ด์ง€๋ฉด? 

(๋‹คํ–‰์Šค๋Ÿฝ๊ฒŒ๋„) ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ๋Š” ์ด๋Ÿฌํ•œ ์ฃฝ์Œ์˜ ๋‹ค์ด์•„๋ชฌ๋“œ ์ƒ์† ๊ตฌ์กฐ๋ฅผ ๋ง‰๊ณ  ์žˆ๋‹ค.

 

์œ„์™€ ๊ฐ™์€ ์ฃฝ์Œ์˜ ๋‹ค์ด์•„๋ชฌ๋“œ ์ƒ์†๊ตฌ์กฐ๊ฐ€ ๋ง‰ํžŒ ์ด์œ ๋Š” ๋ณธ ํฌ์ŠคํŒ… ์ฐธ๊ณ (https://rainbowcode.tistory.com/174)(c#์˜ˆ์ œ์ด๊ธด ํ•˜๋‚˜, ์–ด์ฐจํ”ผ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ์ฃผ์ถ•์ด C#๊ฐœ๋ฐœ์ฃผ์ถ•์ด๋ผ์„œ OOP ์–ธ์–ด ์ฒ ํ•™์ด ์ƒ๋‹นํžˆ ์œ ์‚ฌ๋‹ค๊ณ  ๋ณด๋ฉด ๋˜๋ฏ€๋กœ, ๋…ํ•ด์— ์–ด๋ ค์›€์€ ์—†์„ ๊ฒƒ์ด๋‹ค. 

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ

์œ„ํ‚ค๋ฐฑ๊ณผ
๋ฉ€ํ‹ฐ ํŒจ๋Ÿฌ๋‹ค์ž„: ํ•จ์ˆ˜ํ˜•, ์ œ๋„ค๋ฆญ, ๋ช…๋ นํ˜•, ๊ฐ์ฒด ์ง€ํ–ฅ

๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ
๋• ํƒ€์ดํ•‘, gradual, structural[4]
์•„ํŒŒ์น˜ ๋ผ์ด์„ ์Šค 2.0
.ts, .tsx
www.typescriptlang.org

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ(TypeScript)๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์Šˆํผ์…‹์ธ ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ด๋‹ค. ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ์—์„œ ๊ฐœ๋ฐœ, ์œ ์ง€ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์—„๊ฒฉํ•œ ๋ฌธ๋ฒ•์„ ์ง€์›ํ•œ๋‹ค. C#์˜ ๋ฆฌ๋“œ ์•„ํ‚คํ…ํŠธ์ด์ž ๋ธํŒŒ์ด, ํ„ฐ๋ณด ํŒŒ์Šค์นผ์˜ ์ฐฝ์‹œ์ž์ธ Anders Hejlsberg๊ฐ€ ๊ฐœ๋ฐœ์— ์ฐธ์—ฌํ•œ๋‹ค.[5] ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์™€ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ๋ฅผ ์œ„ํ•œ ๊ฐœ๋ฐœ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์—”์ง„์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์ปค๋‹ค๋ž€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ๊ฒŒ ์„ค๊ณ„๋œ ์–ธ์–ด์ด๋‹ค.[6] ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์Šˆํผ์…‹์ด๊ธฐ ๋•Œ๋ฌธ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ž‘์„ฑ๋œ ํ”„๋กœ๊ทธ๋žจ์ด ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ๋„ ๋™์ž‘ํ•œ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ์—์„œ ์ž์‹ ์ด ์›ํ•˜๋Š” ํƒ€์ž…์„ ์ •์˜ํ•˜๊ณ  ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋ฉด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ปดํŒŒ์ผ๋˜์–ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” ๋ชจ๋“  ์šด์˜ ์ฒด์ œ, ๋ชจ๋“  ๋ธŒ๋ผ์šฐ์ €, ๋ชจ๋“  ํ˜ธ์ŠคํŠธ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์˜คํ”ˆ ์†Œ์Šค์ด๋‹ค.

)

 

๊ฐ์„คํ•˜๊ณ   

์ด์ œ ์ปคํ”ผ๊ฐ€ ์ ์  ๋” ๋งŽ์•„์ง€๋ฉด?

ํ”„๋ ˆ์ฒผ ์ปคํ”ผ๋„ ์ƒˆ๋กœ ์„ ๋ณด์˜€๋Š”๋ฐ ๋ฐ˜์‘์ด ์ข‹์•„์„œ

์šฐ์œ ๊ฐ€ ๋“ค์–ด๊ฐ„ ํ”„๋ ˆ์ฒผ ์ปคํ”ผ๋„ ๊ฐœ๋ฐœํ•˜๊ณ  ๋˜ ๋ฐ˜์‘์ด ํ„ฐ์ ธ์„œ

์šฐ์œ ๊ฐ€ ๋“ค์–ด๊ฐ„ ํ”„๋ ˆ์ฒผ ์ปคํ”ผ์— ์†Œ๊ธˆ๋„ ๋ฟŒ๋ ค์„œ ํŒ๋งคํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด?

๊ณ„์† ์•„๋ž˜๋กœ ์ƒ์†์‹œ์ผœ์ค˜์•ผ ํ• ๊นŒ? ๊ทธ๋ž˜์„œ ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์ง„ ์ปคํ”ผ๋จธ์‹ ๋“ค ๋•Œ๋ฌธ์— ์กฑ๋ณด๊ฐ€ ๋์—†์ด ๊ธธ์–ด์ ธ์„œ ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐ€๊ฒŒ ๋ ๊นŒ?

๋ณธ๊ฒฉ์ ์œผ๋กœ ์กฑ๋ณด๊ฐ€ ๊ผฌ์ด๊ฒŒ ๋œ๋‹ค.

์ƒ์†์ด ๋ฌธ์ œ๋ผ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ์ƒ์†์œผ๋กœ ํ’€๋ ค๊ณ  ํ•˜๋ฉด ๊ผฌ์ธ๋‹ค๋Š” ๋œป์ด๋‹ค.

(์ƒ์†์€ ์ฝ”๋“œ ์ค‘๋ณต์„ ์—†์•ฐ๊ณผ ๋™์‹œ์— ๋‹คํ˜•์„ฑ ๊ตฌํ˜„์„ ์œ„ํ•œ ํ•„์ˆ˜์š”์†Œ ์ค‘ ํ•˜๋‚˜์ด๋‹ค)

 

 

ํŠนํžˆ๋‚˜ ์ƒ์†์€ ์œ„์—์„œ ์•„๋ž˜๋กœ ์ˆ˜์ง์ ์œผ๋กœ ๊ด€๊ณ„๊ฐ€ ํ˜•์„ฑ๋œ๋‹ค.

์ด๋Ÿฌํ•œ ์ƒ์†์˜ ์น˜๋ช…์ ์ธ ๋ฌธ์ œ์ ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์–ด๋–ค ๋ถ€๋ชจํด๋ž˜์Šค์˜ ํ–‰๋™์„ ์ˆ˜์ •ํ•˜๊ฒŒ ๋˜๋ฉด 

์ด ์ˆ˜์ •๋œ ์‚ฌํ•ญ๋•Œ๋ฌธ์— ์ƒ์†๋ฐ›๋Š” ๋ชจ~๋“  ์ž์‹ ํด๋ž˜์Šค๋“ค์ด ์˜ํ–ฅ์„ ๋ฐ›์„ ์ˆ˜๋ฐ–์— ์—†๋Š” ๊ตฌ์กฐ์ด๋‹ค.

(์œ„์—์„œ ๋ฌธ์ œ๊ฐ€ ํ„ฐ์ ธ์„œ ์†๋ณด๋ฉด ์•„๋ž˜๋„ ํ„ฐ์ ธ์„œ ์ผ์ผํžˆ ์ฐพ์•„๊ฐ€์„œ ๊ณ ์ณ์ค˜์•ผ ํ•˜๋Š” ๊ตฌ์กฐ)

 

์ด๋Ÿฌํ•œ ์ƒ์†์˜ ๋ฌธ์ œ์ ๋“ค ๋•Œ๋ฌธ์— ์ƒ์†์ด ๋ถˆํ•„์š”ํ•ด์ง€๋Š” ์„ ์ด ์˜ค๋ฉด, ์ปดํฌ์ง€์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹๋‹ค!

 

 

 

 

<๋ชจ๋“  ๊ฒƒ์„ ๋’ค์—Ž๋Š” ์ปดํฌ์ง€์…˜, Favor Composition over inheritance>

 

 Favor Composition over inheritance 

"์ƒ์† ๋Œ€์‹ ์— ์ปดํฌ์ง€์…˜(๋œป: ๊ตฌ์„ฑ์š”์†Œ๋“ค, ๊ตฌ์„ฑ)์„ ๋” ์„ ํ˜ธํ•˜์„ธ์š”."

 

๋ ˆ๊ณ ์„ฑ์„ ์Œ“์„ ๋•Œ๋งˆ๋‹ค ํ•„์š”ํ•œ ๋ถ€ํ’ˆ๋“ค์„ ํ•˜๋‚˜์”ฉ ๊ฝ‚์•„์„œ ์กฐ๋ฆฝํ•ด๋‚˜๊ฐ€๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ ์ปดํฌ์ง€์…˜๋„ ํ•˜๋‚˜์”ฉ ๊ฝ‚์•„๋‚˜๊ฐ€๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.

์ปดํฌ์ง€์…˜์„ ํ†ตํ•ด ์†Œ๊ธˆ์นดํŽ˜๋ผ๋–ผ๋จธ์‹ ์„ ๋งŒ๋“ค์–ด๋ณธ๋‹ค.

 

์ด๋Ÿฌํ•œ ์ปดํฌ์ง€์…˜์„ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ• ๊นŒ 

 

 

์•„๋ž˜ ์†Œ์Šค์ฝ”๋“œ(์ปคํ”ผ๋จธ์‹ , ์ปคํ”ผ๋จธ์‹ ์„ ์ƒ์†ํ•œ ์นดํŽ˜๋ผ๋–ผ๋จธ์‹ , ์ปคํ”ผ๋จธ์‹ ์„ ์ƒ์†ํ•œ ์†Œ๊ธˆ์ปคํ”ผ๋จธ์‹  ๊ตฌํ˜„๋˜์–ด์žˆ์Œ)์—

์†Œ๊ธˆ์นดํŽ˜๋ผ๋–ผ๋จธ์‹ (๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์ปคํ”ผ๋„ ๋‚ด๋ ค์•ผํ•˜๊ณ , ๋ฐ์šด ์šฐ์œ ๋„ ํ•„์š”ํ•˜๊ณ , ์†Œ๊ธˆ๋„ ํ•œ๊ผฌ์ง‘ ๋„ฃ์€...) ์„ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด?

//   //์ปคํ”ผ๋จธ์‹  ๋งŒ๋“ค๊ธฐ
type CoffeeCup = {
  orderShot: number;
  hasMilk?: boolean;
  hasSalt?: boolean;
};

interface CoffeeMaker {
  makeCoffee(shots: number): CoffeeCup;
}

// CoffeeMaker ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” CoffeMachine ํด๋ž˜์Šค์ด๋‹ค.
class CoffeMachine implements CoffeeMaker {
  protected 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;
  }
}

// CoffeMachine ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ CafeLatteMachine ํด๋ž˜์Šค์ด๋‹ค.

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("์šฐ์œ  ๋ถ“๋Š” ์ค‘...");
  }
}

// CoffeMachine ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ saltCoffeeMachine ํด๋ž˜์Šค์ด๋‹ค.
class saltCoffeeMachine extends CoffeMachine {
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot);

    //์†Œ๊ธˆ์„ ๋ฟŒ๋ฆฐ๋‹ค.
    this.addSalt();
    return {
      ...coffee,
      hasSalt: true,
    };
  }

  addSalt() {
    console.log("์†Œ๊ธˆ์„ ํ•œ๊ผฌ์ง‘");
  }
}

const machines: CoffeeMaker[] = [
  new CoffeMachine(25, 25),
  new CafeLatteMachine(15, 25),
  new saltCoffeeMachine(5, 10),
];

machines.forEach((machine) => {
  console.log("------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!------------");
  console.log(machine.makeCoffee(1));
});

<์ฝ”๋“œ ์ƒˆ์š”์†Œ ์ถ”๊ฐ€์ „ ์ถœ๋ ฅ ๊ฒฐ๊ณผ>

------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!------------
์บก์А์“ฐ๊ธฐ ์ „ 25
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„22
๋ฌผ์“ฐ๊ธฐ ์ „ 25
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 15
๋ฌผ ๋“์ด๋Š” ์ค‘...
{ orderShot: 1, hasMilk: false }
------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!------------
์บก์А์“ฐ๊ธฐ ์ „ 15
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„12
๋ฌผ์“ฐ๊ธฐ ์ „ 25
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 15
๋ฌผ ๋“์ด๋Š” ์ค‘...
์šฐ์œ  ๋ฐ์šฐ๋Š” ์ค‘...
์šฐ์œ  ๋ถ“๋Š” ์ค‘...
{ orderShot: 1, hasMilk: true }
------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!------------
์บก์А์“ฐ๊ธฐ ์ „ 5
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„2
๋ฌผ์“ฐ๊ธฐ ์ „ 10
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 0
๋ฌผ ๋“์ด๋Š” ์ค‘...
์†Œ๊ธˆ์„ ํ•œ๊ผฌ์ง‘
{ orderShot: 1, hasMilk: false, hasSalt: true }

์ƒ์†๋งŒ์„ ์ด์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋ฌด์–ธ๊ฐ€ ์นดํŽ˜๋ผ๋–ผ๋จธ์‹ ์—์„œ ์šฐ์œ ๊ฐ€์ ธ์˜ค๊ณ ~ ์†Œ๊ธˆ์ปคํ”ผ๋จธ์‹ ์—์„œ ์†Œ๊ธˆ๊ฐ€์ ธ์˜ค๊ณ ~ ํ•ด์•ผ๊ฒ ์ง€๋งŒ

์ฐจ๋ผ๋ฆฌ ์šฐ์œ  ๊ฑฐํ’ˆ๊ธฐ ํด๋ž˜์Šค์™€ ์†Œ๊ธˆํ†ต ํด๋ž˜์Šค๊ฐ€ ๋”ฐ๋กœ์žˆ์–ด์„œ ํ•„์š”ํ•  ๋•Œ ๋งˆ๋‹ค ๊ฐ€์ ธ๋‹ค ๋ถ™์ด๋Š” ๊ฒƒ์ด ๋” ํšจ์œจ์ ์ผ ๊ฒƒ์ด๊ณ 

์ปดํฌ์ง€์…˜์€ ๊ทธ๊ฒƒ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ค€๋‹ค!

 

 

 

์šฐ์„  ๋‹ค์Œ๊ณผ ๊ฐ™์ด

ํ‰๋ฒ”ํ•œ ์šฐ์œ  ๊ฑฐํ’ˆ๊ธฐ ํด๋ž˜์Šค์™€ ์†Œ๊ธˆ๋ฏน์„œ ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•ด์ค€๋‹ค.

์šฐ์œ  ๊ฑฐํ’ˆ๊ธฐ ํด๋ž˜์Šค ์ž์ฒด์ ์œผ๋กœ ์šฐ์œ ๊ฑฐํ’ˆ์„ ๋งŒ๋“ค๊ณ , ์™ธ๋ถ€์—์„œ ์ปคํ”ผ์ปต์„ ๋ฐ›์•„์˜ฌ ๊ฒฝ์šฐ ๋‚ด๋ถ€์—์„œ ๋งŒ๋“  ์šฐ์œ ๊ฑฐํ’ˆ์„ ์˜ฌ๋ฆฐ ์ปคํ”ผ์ปต์„ ๋ฐ˜ํ™˜ํ•ด์ค„ ๊ฒƒ์ด๋‹ค.

์†Œ๊ธˆ ๋ฏน์„œ ํด๋ž˜์Šค๋Š” ๋‚ด๋ถ€์—์„œ ์†Œ๊ธˆ์„ ์ง‘์–ด์˜ฌ๋ฆฌ๊ณ , ์™ธ๋ถ€์—์„œ ์ปคํ”ผ์ปต์„ ๋ฐ›์•„์˜ฌ ๊ฒฝ์šฐ ๋‚ด๋ถ€์—์„œ ์ง‘์–ด๋“  ์†Œ๊ธˆ์„ ๋ฟŒ๋ ค ๊ทธ ์ปคํ”ผ์ปต์„ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋„๋ก ๋งŒ๋“ค์–ด๋ณธ๋‹ค. 

//   //์ปคํ”ผ๋จธ์‹  ๋งŒ๋“ค๊ธฐ
type CoffeeCup = {
  orderShot: number;
  hasMilk?: boolean;
  hasSalt?: boolean;
};

interface CoffeeMaker {
  makeCoffee(shots: number): CoffeeCup;
}

//์ผ๋ฐ˜ ์šฐ์œ  ๊ฑฐํ’ˆ๊ธฐ//////////////////////////////////////////////////////////////////////
class CheapMilkSteamer {
  //(1)์šฐ์œ  ๊ฑฐํ’ˆ์„ ๋งŒ๋“œ๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜
  private steamMilk(): void {
    console.log("๋ชฝ๊ธ€๋ชฝ๊ธ€ ํฌ์‚ญํฌ์‚ญํ•œ ์šฐ์œ ํผ");
  }
  //(2)๋งŒ๋“ค์–ด์ง„ ์ปคํ”ผ์ปต์„ ๋ฐ›์•„์„œ, ๋งŒ๋“ค์–ด์ง„ ์šฐ์œ ๊ฑฐํ’ˆ(1)์„ ๋ถ€์–ด์„œ ์ด ์ปคํ”ผ์ปต์„ ๋‹ค์‹œ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜
  addMilkform(cup: CoffeeCup): CoffeeCup {
    this.steamMilk();
    return {
      ...cup,
      hasMilk: true,
    };
  }
}

//์†Œ๊ธˆ๋ฏน์„œ///////////////////////////////////////////////////////////////////////////////
class SaltMixer {
  //(1)์†Œ๊ธˆ์„ ์ง‘๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜
  private getSalt() {
    console.log("์†Œ๊ธˆ์„ ํ•œ๊ผฌ์ง‘ ์ง‘์—ˆ๋‹ค");
    return true;
  }
  //(2)๋งŒ๋“ค์–ด์ง„ ์ปคํ”ผ์ปต์„ ๋ฐ›์•„์„œ, ์ง‘์€ ์†Œ๊ธˆ(1)์„ ๋ฟŒ๋ ค์„œ ์ด ์ปคํ”ผ์ปต์„ ๋‹ค์‹œ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜
  addSalt(cup: CoffeeCup): CoffeeCup {
    const salt = this.getSalt();
    return {
      ...cup,
      hasSalt: salt,
    };
  }
}
// CoffeeMaker ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” CoffeMachine ํด๋ž˜์Šค์ด๋‹ค.
class CoffeMachine implements CoffeeMaker {
  protected 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;
  }
}

// CoffeMachine ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ CafeLatteMachine ํด๋ž˜์Šค์ด๋‹ค.

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("์šฐ์œ  ๋ถ“๋Š” ์ค‘...");
  }
}

// CoffeMachine ํด๋ž˜์Šค ๋ฅผ ์ƒ์†๋ฐ›์€ saltCoffeeMachine ํด๋ž˜์Šค์ด๋‹ค.
class saltCoffeeMachine extends CoffeMachine {
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot);

    //์†Œ๊ธˆ์„ ๋ฟŒ๋ฆฐ๋‹ค.//////////////////////////////////////////////////////////////////////
    this.addSalt();
    return {
      ...coffee,
      hasSalt: true,
    };
  }

  private addSalt() {
    console.log("์†Œ๊ธˆ์„ ํ•œ๊ผฌ์ง‘");
  }
}

const machines: CoffeeMaker[] = [
  new CoffeMachine(25, 25),
  new CafeLatteMachine(15, 25),
  new saltCoffeeMachine(5, 10),
];

machines.forEach((machine) => {
  console.log("------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!------------");
  console.log(machine.makeCoffee(1));
});

 

์—ฌ๊ธฐ๊นŒ์ง€ ๋งŒ๋“ค์—ˆ์œผ๋ฉด ์นดํŽ˜๋ผ๋–ผ๋จธ์‹  ๋‚ด๋ถ€์—์„œ ๊ตณ์ด ์šฐ์œ ๋ฅผ ๋งŒ๋“ค๊ณ  ๋ถ€์–ด์ฃผ๋Š” ๋‚ด๋ถ€ ํ™œ๋™์ด ํ•„์š”ํ•œ์ง€,

์†Œ๊ธˆ์ปคํ”ผ๋จธ์‹  ๋‚ด๋ถ€์—์„œ ๊ตณ์ด ์†Œ๊ธˆ์„ ์ง‘์–ด์„œ ๋ฟŒ๋ ค์ฃผ๋Š” ๋‚ด๋ถ€ ํ™œ๋™์ด ํ•„์š”ํ•œ์ง€์— ๋Œ€ํ•œ ์˜์‹ฌ์ด ํ•„์š”ํ•œ๋‹ค.

 

๋งŒ๋“ค์–ด ๋‘” ์šฐ์œ  ๊ฑฐํ’ˆ๊ธฐ ํด๋ž˜์Šค์™€ ์†Œ๊ธˆ๋ฏน์„œ ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ์„ค๊ณ„์ƒ ๋” ๋‚˜์„ ๋“ฏํ•˜๋‹ค. 

 

 

์นดํŽ˜๋ผ๋–ผ ๋จธ์‹ ๋ถ€ํ„ฐ ๊ณ ์ณ๋ณธ๋‹ค.

 

1. ์นดํŽ˜๋ผ๋–ผ๋จธ์‹  ๋‚ด๋ถ€์—์„œ ์šฐ์œ  ๊ด€๋ จ ๋กœ์ง์„ ๊ฑท์–ด๋‚ธ๋‹ค.

// CoffeMachine ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ CafeLatteMachine ํด๋ž˜์Šค์ด๋‹ค.

class CafeLatteMachine extends CoffeMachine {
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์А ์†Œ๋น„, ๋ฌผ ์†Œ๋น„, ๋ฌผ ๊ฐ€์—ด ๋‹ค ๋๋‚˜๊ณ  ์™„์„ฑ๋œ ์ปคํ”ผ๊ฐ€ ๋ฐ˜ํ™˜

    return {
      ...coffee,
      hasMilk: true,
    };
  }
}

2. ์šฐ์œ  ๊ฑฐํ’ˆ๊ธฐ ํด๋ž˜์Šค์—์„œ ํ•„์š”ํ•œ ๊ฒƒ๋“ค์„ ๋ฐ›์•„์˜ค์ž

์ด๊ฒƒ์€ dependency injection(https://ko.wikipedia.org/wiki/%EC%9D%98%EC%A1%B4%EC%84%B1_%EC%A3%BC%EC%9E%85)

์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค.

// CoffeMachine ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ CafeLatteMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\\

class CafeLatteMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private milkFrother: CheapMilkSteamer
  ) {
    super(capsule, water);
  }

  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์А ์†Œ๋น„, ๋ฌผ ์†Œ๋น„, ๋ฌผ ๊ฐ€์—ด ๋‹ค ๋๋‚˜๊ณ  ์™„์„ฑ๋œ ์ปคํ”ผ๊ฐ€ ๋ฐ˜ํ™˜

    return {
      ...coffee,
      hasMilk: true,
    };
  }
}

3. ์ด์ œ ์ง์ ‘์ ์œผ๋กœ hasMilk ํ”„๋กœํผํ‹ฐ๋ฅผ true๋กœ ๋ณ€๊ฒฝํ•ด์„œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋˜ ๋กœ์ง๋„ ๊ฑท์–ด๋‚ด๊ณ 

milkFrother์— milk๋ฅผ ๋ฐ”๋กœ ์ „๋‹ฌํ•ด์ฃผ์ž.

// CoffeMachine ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ CafeLatteMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\\

class CafeLatteMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private milkFrother: CheapMilkSteamer
  ) {
    super(capsule, water);
  }

  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์А ์†Œ๋น„, ๋ฌผ ์†Œ๋น„, ๋ฌผ ๊ฐ€์—ด ๋‹ค ๋๋‚˜๊ณ  ์™„์„ฑ๋œ ์ปคํ”ผ๊ฐ€ ๋ฐ˜ํ™˜
    return this.milkFrother.addMilkform(coffee);
  }
}

์†Œ๊ธˆ์ปคํ”ผ ๋จธ์‹ ๋„ ์œ„์™€ ๋น„์Šทํ•˜๊ฒŒ ๊ณ ์ณ๋ณธ๋‹ค.

1. ์†Œ๊ธˆ์ปคํ”ผ๋จธ์‹  ๋‚ด๋ถ€์—์„œ ์†Œ๊ธˆ ๊ด€๋ จ ๋กœ์ง์„ ๊ฑท์–ด๋‚ธ๋‹ค.

class saltCoffeeMachine extends CoffeMachine {
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot);
    return {
      ...coffee,
      hasSalt: true,
    };
  }
}

 

2. ์†Œ๊ธˆ๋ฏน์„œ ํด๋ž˜์Šค์—์„œ ํ•„์š”ํ•œ ๊ฒƒ๋“ค์„ ๋ฐ›์•„์˜ค์ž

์ด๊ฒƒ์€ dependency injection(https://ko.wikipedia.org/wiki/%EC%9D%98%EC%A1%B4%EC%84%B1_%EC%A3%BC%EC%9E%85)

์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค.

 

class saltCoffeeMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private saltTopping: SaltMixer
  ) {
    super(capsule, water);
  }
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot);

    return {
      ...coffee,
      hasSalt: true,
    };
  }
}

 

 

3. ์ด์ œ ์ง์ ‘์ ์œผ๋กœ hasMilk ํ”„๋กœํผํ‹ฐ๋ฅผ true๋กœ ๋ณ€๊ฒฝํ•ด์„œ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋˜ ๋กœ์ง๋„ ๊ฑท์–ด๋‚ด๊ณ 

์†Œ๊ธˆํ† ํ•‘์— ์†”ํŠธ๋ฏน์„œ๋ฅผ ๋ฐ”๋กœ ์ „๋‹ฌํ•ด์ฃผ์ž.

class saltCoffeeMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private saltTopping: SaltMixer
  ) {
    super(capsule, water);
  }
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot);
    return this.saltTopping.addSalt(coffee);
  }
}

 

 

<ํ˜„์žฌ๊นŒ์ง€ ์†Œ์Šค์ฝ”๋“œ>

//   //์ปคํ”ผ๋จธ์‹  ๋งŒ๋“ค๊ธฐ
type CoffeeCup = {
  orderShot: number;
  hasMilk?: boolean;
  hasSalt?: boolean;
};

interface CoffeeMaker {
  makeCoffee(shots: number): CoffeeCup;
}

//์ผ๋ฐ˜ ์šฐ์œ  ๊ฑฐํ’ˆ๊ธฐ//////////////////////////////////////////////////////////////////////
class CheapMilkSteamer {
  //(1)์šฐ์œ  ๊ฑฐํ’ˆ์„ ๋งŒ๋“œ๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜
  private steamMilk(): void {
    console.log("๋ชฝ๊ธ€๋ชฝ๊ธ€ ํฌ์‚ญํฌ์‚ญํ•œ ์šฐ์œ ํผ");
  }
  //(2)๋งŒ๋“ค์–ด์ง„ ์ปคํ”ผ์ปต์„ ๋ฐ›์•„์„œ, ๋งŒ๋“ค์–ด์ง„ ์šฐ์œ ๊ฑฐํ’ˆ(1)์„ ๋ถ€์–ด์„œ ์ด ์ปคํ”ผ์ปต์„ ๋‹ค์‹œ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜
  addMilkform(cup: CoffeeCup): CoffeeCup {
    this.steamMilk();
    return {
      ...cup,
      hasMilk: true,
    };
  }
}

//์†Œ๊ธˆ๋ฏน์„œ///////////////////////////////////////////////////////////////////////////////
class SaltMixer {
  //(1)์†Œ๊ธˆ์„ ์ง‘๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜
  private getSalt() {
    console.log("์†Œ๊ธˆ์„ ํ•œ๊ผฌ์ง‘ ์ง‘์—ˆ๋‹ค");
    return true;
  }
  //(2)๋งŒ๋“ค์–ด์ง„ ์ปคํ”ผ์ปต์„ ๋ฐ›์•„์„œ, ์ง‘์€ ์†Œ๊ธˆ(1)์„ ๋ฟŒ๋ ค์„œ ์ด ์ปคํ”ผ์ปต์„ ๋‹ค์‹œ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜
  addSalt(cup: CoffeeCup): CoffeeCup {
    const salt = this.getSalt();
    return {
      ...cup,
      hasSalt: salt,
    };
  }
}
// CoffeeMaker ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” CoffeMachine ํด๋ž˜์Šค์ด๋‹ค.////////////////////////////
class CoffeMachine implements CoffeeMaker {
  protected 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;
  }
}

// CoffeMachine ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ CafeLatteMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\\

class CafeLatteMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private milkFrother: CheapMilkSteamer
  ) {
    super(capsule, water);
  }

  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์А ์†Œ๋น„, ๋ฌผ ์†Œ๋น„, ๋ฌผ ๊ฐ€์—ด ๋‹ค ๋๋‚˜๊ณ  ์™„์„ฑ๋œ ์ปคํ”ผ๊ฐ€ ๋ฐ˜ํ™˜
    return this.milkFrother.addMilkform(coffee);
  }
}

// CoffeMachine ํด๋ž˜์Šค ๋ฅผ ์ƒ์†๋ฐ›์€ saltCoffeeMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\
class saltCoffeeMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private saltTopping: SaltMixer
  ) {
    super(capsule, water);
  }
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot);
    return this.saltTopping.addSalt(coffee);
  }
}

const machines: CoffeeMaker[] = [
  new CoffeMachine(25, 25),
  new CafeLatteMachine(15, 25, new CheapMilkSteamer()),
  new saltCoffeeMachine(5, 10, new SaltMixer()),
];

machines.forEach((machine) => {
  console.log("------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!-- ----------");
  console.log(machine.makeCoffee(1));
});

 

<์ถœ๋ ฅ ๊ฒฐ๊ณผ> awesome!! ! ์•„์ฃผ ์ž˜ ์ž‘๋™ํ•œ๋‹ค.

 


------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!------------
์บก์А์“ฐ๊ธฐ ์ „ 25
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„22
๋ฌผ์“ฐ๊ธฐ ์ „ 25
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 15
๋ฌผ ๋“์ด๋Š” ์ค‘...
{ orderShot: 1, hasMilk: false }
------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!------------
์บก์А์“ฐ๊ธฐ ์ „ 15
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„12
๋ฌผ์“ฐ๊ธฐ ์ „ 25
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 15
๋ฌผ ๋“์ด๋Š” ์ค‘...
๋ชฝ๊ธ€๋ชฝ๊ธ€ ํฌ์‚ญํฌ์‚ญํ•œ ์šฐ์œ ํผ
{ orderShot: 1, hasMilk: true }
------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!------------
์บก์А์“ฐ๊ธฐ ์ „ 5
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„2
๋ฌผ์“ฐ๊ธฐ ์ „ 10
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 0
๋ฌผ ๋“์ด๋Š” ์ค‘...
์†Œ๊ธˆ์„ ํ•œ๊ผฌ์ง‘ ์ง‘์—ˆ๋‹ค
{ orderShot: 1, hasMilk: false, hasSalt: true }

 

์ด๋ ‡๊ฒŒ ๊ฐ๊ฐ์˜ ํด๋ž˜์Šค์—์„œ ํ•„์š”ํ•œ ๊ฒƒ์„ ๋งค๋ฒˆ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ๋งค๋ฒˆ ์ƒ์†์„ ํ•ด์„œ ์ƒˆ๋กœ์šด ์š”์†Œ๋“ค์„ ์ง‘์–ด๋„ฃ๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋‚ด๊ธฐ ๋ณด๋‹ค๋Š”

๊ฐ๊ฐ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐ์ด ๋“ค๋ฉด(์ด ์˜ˆ์ œ์—์„œ๋Š” ์šฐ์œ ๊ฑฐํ’ˆ๊ธฐํด๋ž˜์Šค์™€ ์†Œ๊ธˆ๋ฏน์„œ ํด๋ž˜์Šค)

์ด๋ ‡๊ฒŒ ํด๋ž˜์Šค๋กœ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด๋‘ ์œผ๋กœ์จ ํ•„์š”ํ•œ ๊ณณ์— ๊ฐ€์ ธ๋‹ค๊ฐ€ ๋ถ™์—ฌ์“ฐ๋Š”!

์ปดํฌ์ง€์…˜์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ์„ค๊ณ„์ƒ ๋” ์ด๋กœ์šด ์ ์ด ์žˆ๋‹ค.(์ƒ์†์˜ ๋‚จ๋ฐœ๋ณด๋‹ค๋Š”)

 

์ด๊ฑธ๋กœ ์ œ์ผ ์ฒ˜์Œ์— ๋งŒ๋“ค๊ณ  ์‹ถ์—ˆ๋˜

 

์†Œ๊ธˆ์นดํŽ˜๋ผํ…Œ์ปคํ”ผ๋จธ์‹  ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ?

 

// ์ฒ˜์Œ๋ถ€ํ„ฐ ๋งŒ๋“ค๊ณ  ์‹ถ์—ˆ๋˜ saltCafeLatteCoffeeMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\
class saltCafeLatteCoffeeMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private saltTopping: SaltMixer,
    private milkFrother: CheapMilkSteamer
  ) {
    super(capsule, water);
  }
  makeCoffee(orderShot: number): CoffeeCup {
    let coffee = super.makeCoffee(orderShot);
    coffee = this.saltTopping.addSalt(coffee);
    return this.milkFrother.addMilkform(coffee);
  }

์ด์  ! ๋ถ€ํ’ˆ ๋ถ™์ด๋“ฏ์ด ํด๋ž˜์Šค๋ฅผ ๋”์šฑ ์‰ฝ๊ฒŒ์ฐ์–ด๋‚ผ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค~!!!

์œ„ ํด๋ž˜์Šค๋ฅผ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์“ฐ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค

// ๋งŒ๋“ค๊ณ  ์‹ถ์—ˆ๋˜ saltCafeLatteCoffeeMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\
class saltCafeLatteCoffeeMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private saltTopping: SaltMixer,
    private milkFrother: CheapMilkSteamer
  ) {
    super(capsule, water);
  }
  makeCoffee(orderShot: number): CoffeeCup {
    let coffee = super.makeCoffee(orderShot);
    return this.milkFrother.addMilkform(this.saltTopping.addSalt(coffee));
  }
}

 

์ด๊ฑธ ๋” ์„ธ๋ จ๋˜๊ฒŒ ์ž‘์„ฑํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ •๋ฆฌํ•ด์ค„ ์ˆ˜ ์žˆ๋‹ค.

// CoffeMachine ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ CafeLatteMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\\

class CafeLatteMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private milkFrother: CheapMilkSteamer
  ) {
    super(capsule, water);
  }

  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์А ์†Œ๋น„, ๋ฌผ ์†Œ๋น„, ๋ฌผ ๊ฐ€์—ด ๋‹ค ๋๋‚˜๊ณ  ์™„์„ฑ๋œ ์ปคํ”ผ๊ฐ€ ๋ฐ˜ํ™˜
    const saltAdded = this.milkFrother.addMilkform(coffee);
    return this.milkFrother.addMilkform(saltAdded);
  }
}

 

<์ตœ์ข… ์ „์ฒด ์ฝ”๋“œ>

//   //์ปคํ”ผ๋จธ์‹  ๋งŒ๋“ค๊ธฐ
type CoffeeCup = {
  orderShot: number;
  hasMilk?: boolean;
  hasSalt?: boolean;
};

interface CoffeeMaker {
  makeCoffee(shots: number): CoffeeCup;
}

//์ผ๋ฐ˜ ์šฐ์œ  ๊ฑฐํ’ˆ๊ธฐ//////////////////////////////////////////////////////////////////////
class CheapMilkSteamer {
  //(1)์šฐ์œ  ๊ฑฐํ’ˆ์„ ๋งŒ๋“œ๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜
  private steamMilk(): void {
    console.log("๋ชฝ๊ธ€๋ชฝ๊ธ€ ํฌ์‚ญํฌ์‚ญํ•œ ์šฐ์œ ํผ");
  }
  //(2)๋งŒ๋“ค์–ด์ง„ ์ปคํ”ผ์ปต์„ ๋ฐ›์•„์„œ, ๋งŒ๋“ค์–ด์ง„ ์šฐ์œ ๊ฑฐํ’ˆ(1)์„ ๋ถ€์–ด์„œ ์ด ์ปคํ”ผ์ปต์„ ๋‹ค์‹œ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜
  addMilkform(cup: CoffeeCup): CoffeeCup {
    this.steamMilk();
    return {
      ...cup,
      hasMilk: true,
    };
  }
}

//์†Œ๊ธˆ๋ฏน์„œ///////////////////////////////////////////////////////////////////////////////
class SaltMixer {
  //(1)์†Œ๊ธˆ์„ ์ง‘๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜
  private getSalt() {
    console.log("์†Œ๊ธˆ์„ ํ•œ๊ผฌ์ง‘ ์ง‘์—ˆ๋‹ค");
    return true;
  }
  //(2)๋งŒ๋“ค์–ด์ง„ ์ปคํ”ผ์ปต์„ ๋ฐ›์•„์„œ, ์ง‘์€ ์†Œ๊ธˆ(1)์„ ๋ฟŒ๋ ค์„œ ์ด ์ปคํ”ผ์ปต์„ ๋‹ค์‹œ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜
  addSalt(cup: CoffeeCup): CoffeeCup {
    const salt = this.getSalt();
    return {
      ...cup,
      hasSalt: salt,
    };
  }
}
// CoffeeMaker ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” CoffeMachine ํด๋ž˜์Šค์ด๋‹ค.////////////////////////////
class CoffeMachine implements CoffeeMaker {
  protected 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;
  }
}

// CoffeMachine ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์€ CafeLatteMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\\

class CafeLatteMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private milkFrother: CheapMilkSteamer
  ) {
    super(capsule, water);
  }

  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot); //๊ธฐ๋ณธ์ ์ธ ์บก์А ์†Œ๋น„, ๋ฌผ ์†Œ๋น„, ๋ฌผ ๊ฐ€์—ด ๋‹ค ๋๋‚˜๊ณ  ์™„์„ฑ๋œ ์ปคํ”ผ๊ฐ€ ๋ฐ˜ํ™˜
    return this.milkFrother.addMilkform(coffee);
  }
}

// CoffeMachine ํด๋ž˜์Šค ๋ฅผ ์ƒ์†๋ฐ›์€ saltCoffeeMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\
class saltCoffeeMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private saltTopping: SaltMixer
  ) {
    super(capsule, water);
  }
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot);
    return this.saltTopping.addSalt(coffee);
  }
}

// ๋งŒ๋“ค๊ณ  ์‹ถ์—ˆ๋˜ saltCafeLatteCoffeeMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\
class saltCafeLatteCoffeeMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private saltTopping: SaltMixer,
    private milkFrother: CheapMilkSteamer
  ) {
    super(capsule, water);
  }
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot);
    const saltAdded = this.saltTopping.addSalt(coffee);
    return this.milkFrother.addMilkform(saltAdded);
  }
}

const machines: CoffeeMaker[] = [
  new CoffeMachine(25, 25),
  new CafeLatteMachine(15, 25, new CheapMilkSteamer()),
  new saltCoffeeMachine(5, 10, new SaltMixer()),
  new saltCafeLatteCoffeeMachine(
    5,
    10,
    new SaltMixer(),
    new CheapMilkSteamer()
  ),
];

machines.forEach((machine) => {
  console.log("------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!-- ----------");
  console.log(machine.makeCoffee(1));
});

<์ถœ๋ ฅ ๊ฒฐ๊ณผ>


------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!-- ----------
์บก์А์“ฐ๊ธฐ ์ „ 25
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„22
๋ฌผ์“ฐ๊ธฐ ์ „ 25
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 15
๋ฌผ ๋“์ด๋Š” ์ค‘...
{ orderShot: 1, hasMilk: false }
------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!-- ----------
์บก์А์“ฐ๊ธฐ ์ „ 15
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„12
๋ฌผ์“ฐ๊ธฐ ์ „ 25
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 15
๋ฌผ ๋“์ด๋Š” ์ค‘...
๋ชฝ๊ธ€๋ชฝ๊ธ€ ํฌ์‚ญํฌ์‚ญํ•œ ์šฐ์œ ํผ
{ orderShot: 1, hasMilk: true }
------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!-- ----------
์บก์А์“ฐ๊ธฐ ์ „ 5
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„2
๋ฌผ์“ฐ๊ธฐ ์ „ 10
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 0
๋ฌผ ๋“์ด๋Š” ์ค‘...
์†Œ๊ธˆ์„ ํ•œ๊ผฌ์ง‘ ์ง‘์—ˆ๋‹ค
{ orderShot: 1, hasMilk: false, hasSalt: true }
------------์ปคํ”ผ๋จธ์‹  ๊ฐ€๋™~!-- ----------
์บก์А์“ฐ๊ธฐ ์ „ 5
์บก์А์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
์บก์А ์“ฐ๊ณ  ๋‚œ ํ›„2
๋ฌผ์“ฐ๊ธฐ ์ „ 10
๋ฌผ์“ฐ๋Ÿฌ์™”์Šต๋‹ˆ๋‹ค.
๋ฌผ์“ฐ๊ณ  ๋‚œ ํ›„ 0
๋ฌผ ๋“์ด๋Š” ์ค‘...
์†Œ๊ธˆ์„ ํ•œ๊ผฌ์ง‘ ์ง‘์—ˆ๋‹ค
๋ชฝ๊ธ€๋ชฝ๊ธ€ ํฌ์‚ญํฌ์‚ญํ•œ ์šฐ์œ ํผ
{ orderShot: 1, hasMilk: true, hasSalt: true }

 

 

<์ตœ์ข… ์š”์•ฝ>

 

// ๋งŒ๋“ค๊ณ  ์‹ถ์—ˆ๋˜ saltCafeLatteCoffeeMachine ํด๋ž˜์Šค์ด๋‹ค.\\\\\\\\\\\\\\\\\\\\\\\\\\\
class saltCafeLatteCoffeeMachine extends CoffeMachine {
  public constructor(
    protected capsule: number = 3,
    protected water: number = 10,
    private saltTopping: SaltMixer,
    private milkFrother: CheapMilkSteamer
  ) {
    super(capsule, water);
  }
  makeCoffee(orderShot: number): CoffeeCup {
    const coffee = super.makeCoffee(orderShot);
    const saltAdded = this.saltTopping.addSalt(coffee);
    return this.milkFrother.addMilkform(saltAdded);
  }
}

์ด ํด๋ž˜์Šค๋Š” ์šฐ์œ ๋ฅผ ์–ด๋–ป๊ฒŒ ๋งŒ๋“œ๋Š”์ง€ ์†Œ๊ธˆ์€ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌ๋˜๋Š”๊ฑด์ง€ ์ „ํ˜€ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๋Š”๋‹ค.

๋‹ค๋งŒ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์„ ๊ฐ€์ ธ์™€์„œ ์™ธ๋ถ€์—์„œ ์ฃผ์ž…๋ฐ›์Œ์œผ๋กœ์จ

์ปดํฌ์ง€์…˜์„ ์ด์šฉํ•ด์„œ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์„ ๊ณ„์† ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ปดํฌ์ง€์…˜์€ ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๊ต‰์žฅํžˆ ๋†’์—ฌ์ฃผ๋Š” ํšจ๊ณผ๊ฐ€ ์žˆ๋‹ค.

๋‹ค๋งŒ, ์น˜๋ช…์ ์ธ ๋‹จ์ ์ด ์žˆ๋Š”๋ฐ ์šฐ์œ ๊ฑฐํ’ˆ๊ธฐ ํด๋ž˜์Šค, ์†Œ๊ธˆ๋ฏน์„œํด๋ž˜์Šค, ์นดํŽ˜๋ผ๋–ผ๋จธ์‹ , ์†Œ๊ธˆ์ปคํ”ผ๋จธ์‹ , ์†Œ๊ธˆ์นดํŽ˜๋ผ๋–ผ๋จธ์‹  ์ด๋ ‡๊ฒŒ ์—ฐ๊ฒฐ๋œ ํด๋ž˜์Šค๋“ค ๊ฐ„์˜ ์ปคํ”Œ๋ง์ด ๋„ˆ๋ฌด ์‹ฌํ•˜๊ณ  ๊ฐ•๋ ฅํ•œ ์ ์ด ๋ฐ”๋กœ ๊ทธ๊ฒƒ์ด๋‹ค.

๋ฐ”๋กœ ๊ทธ ์šฐ์œ ๊ฑฐํ’ˆ๊ธฐ ํด๋ž˜์Šค์™€ ๋ฐ”๋กœ ๊ทธ ์†Œ๊ธˆ๋ฏน์„œ ํด๋ž˜์Šค๋งŒ์„ ์‚ฌ์šฉํ•ด์•ผํ•˜๋ฉฐ(ํ•ญ์ƒ ์Šค์Šค๋กœ๋ฅผ ์ œ์•ฝ),

๋‹ค๋ฅธ ๊ณ ๊ธ‰์šฐ์œ ๊ฑฐํ’ˆ๊ธฐํด๋ž˜์Šค ์„คํƒ•๋ฏน์„œ ํด๋ž˜์Šค ๋“ฑ์œผ๋กœ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ํด๋ž˜์Šค ๋‚ด์šฉ์„ ๋‹ค์‹œ ๊ณ ์ณ์•ผํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ํด๋ž˜์Šค ๊ฐ„ ์„œ๋กœ ๋„ˆ๋ฌด ์ž˜์•Œ๊ณ  ์žˆ๋Š” ๊ด€๊ณ„ํ˜•์„ฑ์€ ๊ฑด๊ฐ•ํ•˜์ง€ ๋ชปํ•˜๋‹ค.

ํ•จ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋ฐ”๊พธ๋ฉด ๊ทธ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ปคํ”Œ๋ง์ด ๊ฐ•ํ•œ ๋ชจ๋“  ํด๋ž˜์Šค๋“ค์„ ์—…๋ฐ์ดํŠธํ•ด์•ผํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

 

๊ทธ๋ ‡๋‹ค๋ฉด ์ด๋Ÿฌํ•œ ํด๋ž˜์Šค ๊ฐ„ ๊ฒฐํ•ฉ๋„๊ฐ€ ๋†’์€ ๋ฌธ์ œ ์ƒํ™ฉ๋“ค(์ปคํ”Œ๋ง)์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€?

๋”์šฑ ํ™•์žฅ์ด ๊ฐ€๋Šฅํ•˜๊ณ  ์œ ์—ฐ์„ฑ ๋†’์€ ํ…Œํฌ๋‹‰์€ interface(๋ฐ”๋กœ ๋‹ค์Œ ํฌ์ŠคํŒ…, ์ด์™€ ๊ด€๋ จํ•œ ์ „๋žตํŒจํ„ด [ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ] composition ์žฅ์ ์„ ๊ทน๋Œ€ํ™”ํ•˜๋Š” ๊ฐ•๋ ฅํ•œ interface — My dev Note๐Ÿ“’ (tistory.com))๋กœ ๊ตฌ์‚ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

728x90