Post

๐ŸŽจ 06. ์ปค๋งจ๋“œ ํŒจํ„ด

๐ŸŽจ 06. ์ปค๋งจ๋“œ ํŒจํ„ด

๐ŸŽฎ ๋งŒ๋Šฅ IOT ๋ฆฌ๋ชจ์ปจ

์ด ๋ฆฌ๋ชจ์ปจ์€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๊ฐ€๋Šฅํ•œ 7๊ฐœ์˜ ์Šฌ๋กฏ๊ณผ ๊ฐ ์Šฌ๋กฏ์— ํ• ๋‹น๋œ ๊ธฐ๋Šฅ์„ ์ผœ๊ณ  ๋„๋Š” ON/OFF ์Šค์œ„์น˜๊ฐ€ ์žˆ๋‹ค. ๊ฐ ์Šฌ๋กฏ์€ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ€์ •์šฉ ๊ธฐ๊ธฐ์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๊ณ , ์ž‘์—… ์ทจ์†Œ ๋ฒ„ํŠผ๋„ ์žฅ์ฐฉ๋˜์–ด ์žˆ๋‹ค.

๋ฆฌ๋ชจ์ปจ ๊ตฌ์กฐ๋ฅผ ์‚ดํŽด๋ณด์ž

  • ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด ๊ฐ€๋Šฅํ•œ 7๊ฐœ์˜ ์Šฌ๋กฏ์ด ์žˆ๋‹ค. ๊ฐ ์Šฌ๋กฏ์— ์›ํ•˜๋Š” ์ œํ’ˆ์„ ์—ฐ๊ฒฐํ•œ ๋‹ค์Œ ์˜†์— ์žˆ๋Š” ๋ฒ„ํŠผ์œผ๋กœ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • 7๊ฐœ์˜ ์Šฌ๋กฏ๋งˆ๋‹ค โ€˜ONโ€™ ๋ฒ„ํŠผ๊ณผ โ€˜OFFโ€™ ๋ฒ„ํŠผ์ด ์žˆ๋‹ค.
    • ์ด ๋‘ ๋ฒ„ํŠผ์œผ๋กœ ๊ฐ๊ฐ์˜ ์Šฌ๋กฏ์— ์—ฐ๊ฒฐ๋œ ๊ฐ€์ „์ œํ’ˆ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ˆ„๋ฅธ ๋ฒ„ํŠผ์˜ ๋ช…๋ น์„ ์ทจ์†Œํ•˜๋Š” โ€˜UNDOโ€™ ๋ฒ„ํŠผ๋„ ์žˆ๋‹ค.

๐ŸŽฎ ํ˜‘๋ ฅ ์—…์ฒด ํด๋ž˜์Šค ์‚ดํŽด๋ณด๊ธฐ

CEO๊ฐ€ ์ด๋ฉ”์ผ์— ์ฒจ๋ถ€ํ•ด์„œ ๋ณด๋‚ธ, ํ˜‘๋ ฅ ์—…์ฒด ํด๋ž˜์Šค๋ฅผ ์‚ดํŽด๋ณด์ž.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class OutdoorLight {
  on() {
    console.log("์กฐ๋ช…์ด ์ผœ์กŒ์Šต๋‹ˆ๋‹ค");
  }

  off() {
    console.log("์กฐ๋ช…์ด ๊บผ์กŒ์Šต๋‹ˆ๋‹ค");
  }
}

class Stereo {
  on() {
    console.log("์˜ค๋””์˜ค๊ฐ€ ์ผœ์กŒ์Šต๋‹ˆ๋‹ค");
  }

  off() {
    console.log("์˜ค๋””์˜ค๊ฐ€ ๊บผ์กŒ์Šต๋‹ˆ๋‹ค");
  }

  setCd() {
    console.log("CD๊ฐ€ ์žฌ์ƒ๋ฉ๋‹ˆ๋‹ค");
  }

  setVolume(volume: number) {
    console.log(`๋ณผ๋ฅจ์ด ${volume}๋กœ ์„ค์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค`);
  }
}

class TV {
  on() {
    console.log("TV๊ฐ€ ์ผœ์กŒ์Šต๋‹ˆ๋‹ค");
  }

  off() {
    console.log("TV๊ฐ€ ๊บผ์กŒ์Šต๋‹ˆ๋‹ค");
  }
  
  setInputChannel(channel: number) {
	  console.log("์ฑ„๋„์ด ${channel}๋ฒˆ์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.")
	 }
}

๊ณตํ†ต์ ์ธ ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์žˆ์ง€๋„ ์•Š์„ ๋ฟ๋”๋Ÿฌ, ์•ž์œผ๋กœ๋„ ์ด๋Ÿฐ ํด๋ž˜์Šค๋“ค์ด ๋” ์ถ”๊ฐ€๋  ์ˆ˜๋„ ์žˆ๋‹ค.

๐ŸŽฎ ์ปค๋งจ๋“œ ํŒจํ„ด ์†Œ๊ฐœ

๊ฐ์ฒด๋งˆ์„ ์‹๋‹น์—์„œ๋Š” ์ฃผ๋ฌธ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ƒˆ๋กœ์šด ์‹œ์Šคํ…œ์„ ๋„์ž…ํ–ˆ๋‹ค.

๊ธฐ์กด ์Œ์‹ ์ฃผ๋ฌธ ๊ณผ์ •

  • ๊ณ ๊ฐ์ด ์ข…์—…์›์—์„œ ์ฃผ๋ฌธํ•œ๋‹ค.
  • ์ข…์—…์›์€ ์ฃผ๋ฌธ์„ ๋ฐ›์•„์„œ ์นด์šดํ„ฐ์— ์ „๋‹ฌํ•˜๊ณ  โ€œ์ฃผ๋ฌธ ๋“ค์–ด์™”์–ด์š”!โ€ ๋ผ๊ณ  ์–˜๊ธฐํ•œ๋‹ค.
  • ์ฃผ๋ฐฉ์žฅ์ด ์ฃผ๋ฌธ๋Œ€๋กœ ์Œ์‹์„ ์ค€๋น„ํ•œ๋‹ค.

๊ฐ์ฒด๋งˆ์„ ์‹๋‹น์ธ ๋งŒํผ ๊ฐ์ฒด์™€ ๋ฉ”์†Œ๋“œ๋ฅผ ํ™œ์šฉํ•ด ๋ณด์ž.

  • ๊ณ ๊ฐ์ด ์›ํ•˜๋Š” ๊ฒƒ์„ ์ฃผ๋ฌธํ•œ๋‹ค.
  • ์ฃผ๋ฌธ์€ ์ฃผ๋ฌธ์„œ์™€ ๊ทธ ์œ„์— ์ ํ˜€ ์žˆ๋Š” ์ฃผ๋ฌธ ๋‚ด์šฉ์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.
  • ์ข…์—…์›์€ ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ๋ฅผ ์ค€๋น„ํ•˜๋Š” orderUp() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
  • Order ๊ฐ์ฒด์—๋Š” ์Œ์‹์„ ์ค€๋น„ํ•  ๋•Œ ํ•„์š”ํ•œ ๋ชจ๋“  ์ง€์‹œ์‚ฌํ•ญ์ด ๋“ค์–ด์žˆ๋‹ค. Order ๊ฐ์ฒด๊ฐ€ ์ฃผ๋ฐฉ์žฅ์—๊ฒŒ makeBurger() ๊ฐ™์€ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ๋กœ ํ–‰๋™์„ ์ง€์‹œํ•œ๋‹ค.
  • ์ฃผ๋ฐฉ์žฅ์€ Order๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ ์ง€์‹œ์‚ฌํ•ญ์— ๋”ฐ๋ผ์„œ ์Œ์‹์„ ์ค€๋น„ํ•œ๋‹ค.

๐ŸŽฎ ๊ฐ์ฒด๋งˆ์„ ์‹๋‹น ๋“ฑ์žฅ์ธ๋ฌผ์˜ ์—ญํ• 

  • ์ฃผ๋ฌธ์„œ๋Š” ์ฃผ๋ฌธ ๋‚ด์šฉ์„ ์บก์Аํ™”ํ•œ๋‹ค.
    • ์ฃผ๋ฌธ ๋‚ด์šฉ์„ ์š”๊ตฌํ•˜๋Š” ๊ฐ์ฒด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฐ์ฒด์˜ ์ธํ„ฐํŽ˜์ด์Šค์—๋Š” ์‹์‚ฌ ์ค€๋น„์— ํ•„์š”ํ•œ ํ–‰๋™์„ ์บก์Аํ™”ํ•œ orderUp() ๋ฉ”์†Œ๋“œ๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.
  • ์ข…์—…์›์€ ์ฃผ๋ฌธ์„œ๋ฅผ ๋ฐ›๊ณ  orderUp() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
    • ์ข…์—…์›์€ ์ฃผ๋ฌธ์„œ์— ๋ฌด์Šจ ๋‚ด์šฉ์ด ์žˆ๋Š”์ง€, ๋ˆ„๊ฐ€ ์‹์‚ฌ๋ฅผ ์ค€๋น„ํ•˜๋Š”์ง€๋Š” ์ „ํ˜€ ์•Œ ํ•„์š”๊ฐ€ ์—†๋‹ค. ์ข…์—…์›์˜ takeOrder() ๋ฉ”์†Œ๋“œ์—๋Š” ์—ฌ๋Ÿฌ ๊ณ ๊ฐ์˜ ์ฃผ๋ฌธ์„œ๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌํ•œ๋‹ค.
  • ์ฃผ๋ฐฉ์žฅ์€ ์‹์‚ฌ๋ฅผ ์ค€๋น„ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค.
    • ์ข…์—…์›์ด orderUp() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์ฃผ๋ฐฉ์žฅ์ด ๊ทธ ์ฃผ๋ฌธ์„ ๋ฐ›์•„์„œ ์Œ์‹์„ ๋งŒ๋“ค ๋•Œ ํ•„์š”ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ์ „๋ถ€ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ ์ฃผ๋ฐฉ์žฅ๊ณผ ์ข…์—…์›์€ ์™„์ „ํžˆ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๋‹ค.

๊ฐ์ฒด๋งˆ์„ ์‹๋‹น์€ ๊ฐ์ฒด์ง€ํ–ฅ ๋””์ž์ธ ํŒจํ„ด์˜ ํ•ญ ๋ชจ๋ธ์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋ฆฌ๋ชจ์ปจ API์— ๋Œ€์ž…ํ•ด ๋ณด๋ฉด, ๋ฆฌ๋ชจ์ปจ ๋ฒ„ํŠผ์ด ๋ˆŒ๋ ธ์„ ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ์ฝ”๋“œ์™€ ์‹ค์ œ๋กœ ์ผ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. ๋ฆฌ๋ชจ์ปจ ์Šฌ๋กฏ์— ๊ฐ์ฒด๋งˆ์„ ์‹๋‹น์˜ ์ฃผ๋ฌธ์„œ ๊ฐ™์€ ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด์žˆ๋‹ค๋ฉด ์–ด๋–จ๊นŒ?

๐ŸŽฎ ๊ฐ์ฒด๋งˆ์„ ์‹๋‹น๊ณผ ์ปค๋งจ๋“œ ํŒจํ„ด

Image

  • ํด๋ผ์ด์–ธํŠธ๋Š” ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค. ์ปค๋งจ๋“œ ๊ฐ์ฒด๋Š” ๋ฆฌ์‹œ๋ฒ„์— ์ „๋‹ฌํ•  ์ผ๋ จ์˜ ํ–‰๋™์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.
  • ์ปค๋งจ๋“œ ๊ฐ์ฒด์—๋Š” ํ–‰๋™๊ณผ ๋ฆฌ์‹œ๋ฒ„์˜ ์ •๋ณด๊ฐ€ ๊ฐ™์ด ๋“ค์–ด์žˆ๋‹ค.
  • ์ปค๋งจ๋“œ ๊ฐ์ฒด์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋Š” execute() ํ•˜๋‚˜๋ฟ์ด๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” ํ–‰๋™์„ ์บก์Аํ™”ํ•˜๋ฉฐ, ๋ฆฌ์‹œ๋ฒ„์— ์žˆ๋Š” ํŠน์ • ํ–‰๋™์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ๋Š” ์ธ๋ณด์ปค ๊ฐ์ฒด์˜ setCommand() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š”๋ฐ, ์ด๋•Œ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค. ๊ทธ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋Š” ๋‚˜์ค‘์— ์“ฐ์ด๊ธฐ ์ „๊นŒ์ง€ ์ธ๋ณด์ปค ๊ฐ์ฒด์— ๋ณด๊ด€๋œ๋‹ค.
  • ์ธํฌ์ปค์—์„œ ์ปค๋งจ๋“œ ๊ฐ์ฒด์˜ execute() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ฆฌ์‹œ๋ฒ„์— ์žˆ๋Š” ํ–‰๋™ ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

์ธ๋ณด์ปค ๋กœ๋”ฉ

  • ํด๋ผ์ด์–ธํŠธ์—์„œ ์ปค๋งจ๋“œ ๊ฐ์ฒด ์ƒ์„ฑ
  • setCommand()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ธ๋ณด์ปค์— ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ์ €์žฅ
  • ๋‚˜์ค‘์— ํด๋ผ์ด์–ธํŠธ์—์„œ ์ธ๋ณด์ปค์—๊ฒŒ ๊ทธ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ผ๊ณ  ์š”์ฒญ
  • ์ฐธ๊ณ : ์–ด๋–ค ๋ช…๋ น์„ ์ธ๋ณด์ปค์— ๋กœ๋”ฉํ•œ ๋‹ค์Œ ํ•œ ๋ฒˆ๋งŒ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ์ง€์šฐ๋„๋ก ํ•  ์ˆ˜๋„ ์žˆ๊ณ , ์ €์žฅํ•ด ๋‘” ๋ช…๋ น์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

๐ŸŽฎ ์ฒซ ๋ฒˆ์งธ ์ปค๋งจ๋“œ ๊ฐ์ฒด ๋งŒ๋“ค๊ธฐ

๋จผ์ € ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค์ธย Command๋ฅผ ์ •์˜ํ•ด ๋ณด์ž. ๋ชจ๋“  ์ปค๋งจ๋“œ ๊ฐ์ฒด๋Š” ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

1
2
3
interface Command {
  execute(): void
}

์ด์ œ ์กฐ๋ช…์„ ์ผค ๋•Œ ํ•„์š”ํ•œ ์ปค๋งจ๋“œ ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•ด ๋ณด์ž. ํ˜‘๋ ฅ ์—…์ฒด์—์„œ ์ œ๊ณตํ•œ ํด๋ž˜์Šค๋ฅผ ๋ณด๋‹ˆ Light ํด๋ž˜์Šค์—๋Š” on()๊ณผ off()๋ผ๋Š” 2๊ฐœ์˜ ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๋‹ค.

1
2
3
4
5
6
7
class LightOnCommand implements Command {
  constructor(private light: OutdoorLight) {}

  execute() {
    this.light.on()
  }
}

์ƒ์„ฑ์ž์— ์ปค๋งจ๋“œ ๊ฐ์ฒด๋กœ ์ œ์–ดํ•  ํŠน์ • ์กฐ๋ช…(โ€™๊ฑฐ์‹ค ์กฐ๋ช…โ€™ ๋“ฑ)์˜ ์ •๋ณด๊ฐ€ ์ „๋‹ฌ๋œ๋‹ค. ๊ทธ ๊ฐ์ฒด๋Š” light๋ผ๋Š” ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜์— ์ €์žฅ์ด ๋œ๋‹ค. execute() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด light ๊ฐ์ฒด๊ฐ€ ๋ฐ”๋กœ ๊ทธ ์š”์ฒญ์˜ ๋ฆฌ์‹œ๋ฒ„๊ฐ€ ๋œ๋‹ค.

execute() ๋ฉ”์†Œ๋“œ๋Š” ๋ฆฌ์‹œ๋ฒ„ ๊ฐ์ฒด์— ์žˆ๋Š” on() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

๐ŸŽฎ ์ปค๋งจ๋“œ ๊ฐ์ฒด ์‚ฌ์šฉํ•˜๊ธฐ

์ œ์–ดํ•  ๊ธฐ๊ธฐ๋ฅผ ์—ฐ๊ฒฐํ•  ์Šฌ๋กฏ๊ณผ ๋ฒ„ํŠผ์ด ๊ฐ๊ฐ ํ•˜๋‚˜์”ฉ๋ฐ–์— ์—†๋Š” ๋ฆฌ๋ชจ์ปจ์— ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์ž.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface Command {
  execute(): void;
}

class SimpleRemoteControl {
  private slot: Command | null = null;

  setCommand(command: Command) {
    this.slot = command;
  }

  buttonWasPressed() {
    this.slot?.execute();
  }
}

  • ์ปค๋งจ๋“œ๋ฅผ ์ €์žฅํ•  ์Šฌ๋กฏ์ด 1๊ฐœ ์žˆ๋‹ค. ์ด ์Šฌ๋กฏ์œผ๋กœ 1๊ฐœ์˜ ๊ธฐ๊ธฐ๋ฅผ ์ œ์–ดํ•œ๋‹ค.
  • ์Šฌ๋กฏ์„ ๊ฐ€์ง€๊ณ  ์ œ์–ดํ•  ๋ช…๋ น์„ ์„ค์ •ํ•˜๋Š” ๋ฉ”์†Œ๋“œ(setCommand)
    • ๋ฆฌ๋ชจ์ปจ ๋ฒ„ํŠผ์˜ ๊ธฐ๋Šฅ์„ ๋ฐ”๊พธ๊ณ  ์‹ถ๋‹ค๋ฉด ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์–ผ๋งˆ๋“ ์ง€ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด buttonWasPressed()๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค. ์ง€๊ธˆ ์Šฌ๋กฏ์— ์—ฐ๊ฒฐ๋œ ์ปค๋งจ๋“œ ๊ฐ์ฒด์˜ execute() ๋ฉ”์†Œ๋“œ๋งŒ ํ˜ธ์ถœํ•˜๋ฉด ๋œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
function simpleRemoteControlTest() {
  const remoteControl = new SimpleRemoteControl(); // ์ธ๋ณด์ปค
  const light = new Light();                       // ๋ฆฌ์‹œ๋ฒ„
  const lightOn = new LightOnCommand(light);       // ์ปค๋งจ๋“œ ๊ฐ์ฒด

  remoteControl.setCommand(lightOn);               // ์ปค๋งจ๋“œ ์„ค์ •
  remoteControl.buttonWasPressed();                // ์ปค๋งจ๋“œ ์‹คํ–‰
}

simpleRemoteControlTest();

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์จ์„œ SimpleRemoteControl๋ฅผ ํ…Œ์ŠคํŠธํ•ด ๋ณด์ž.

  • ๋ฆฌ๋ชจ์ปจ ์ƒ์„ฑ (์ธ๋ณด์ปค): ๋ช…๋ น์„ ๋ณด๊ด€ํ•˜๊ณ , ์‹คํ–‰์„ ์š”์ฒญํ•˜๋Š” ๊ฐ์ฒด
  • ๋ถˆ ๋งŒ๋“ค๊ธฐ (๋ฆฌ์‹œ๋ฒ„): ์‹ค์ œ ์ผ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ์ฒด
  • ๋ช…๋ น์„œ ๋งŒ๋“ค๊ธฐ (์ปค๋งจ๋“œ ๊ฐ์ฒด): ๋ฆฌ์‹œ๋ฒ„์—๊ฒŒ ์ผ์„ ์‹œํ‚ค๋Š” ๋ช…๋ น์„œ ์—ญํ• . execute() ๋ฉ”์„œ๋“œ ์•ˆ์— โ€œ๋ฌด์—‡์„ ํ• ์ง€โ€ ์ ํ˜€ ์žˆ์Œ
  • ๋ฆฌ๋ชจ์ปจ์— ๋ช…๋ น์„œ ๊ฝ‚๊ธฐ (์ปค๋งจ๋“œ ์„ค์ •) โ†’ ๋ฒ„ํŠผ ๋ˆ„๋ฅด๊ธฐ (์ปค๋งจ๋“œ ์‹คํ–‰)

GarageDoorOpenCommand ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์ฐจ๊ณ  ๋ฌธ์„ ์—ด์–ด ๋ณด์ž.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// ๋ฆฌ์‹œ๋ฒ„: ์‹ค์ œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํด๋ž˜์Šค
class GarageDoor {
  lightOn() {
    console.log("์ฐจ๊ณ  ๋ถˆ์ด ์ผœ์กŒ์Šต๋‹ˆ๋‹ค");
  }

  garageOpen() {
    console.log("์ฐจ๊ณ  ๋ฌธ์ด ์—ด๋ ธ์Šต๋‹ˆ๋‹ค");
  }
}

// ์ปค๋งจ๋“œ ์ธํ„ฐํŽ˜์ด์Šค
interface Command {
  execute(): void;
}

// ์ปค๋งจ๋“œ ๊ตฌํ˜„: ์ฐจ๊ณ  ๋ฌธ ์—ด๊ธฐ
class GarageDoorOpenCommand implements Command {
  constructor(private garageDoor: GarageDoor) {}

  execute() {
    this.garageDoor.garageOpen();
  }
}

// ์ปค๋งจ๋“œ: ์ฐจ๊ณ  ๋ถˆ ์ผœ๊ธฐ
class GarageDoorLightOnCommand implements Command {
  constructor(private garageDoor: GarageDoor) {}

  execute() {
    this.garageDoor.lightOn();
  }
}

// ์ธ๋ณด์ปค: ์ปค๋งจ๋“œ๋ฅผ ์„ค์ •ํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๋ฆฌ๋ชจ์ปจ
class SimpleRemoteControl {
  private slot: Command | null = null;

  setCommand(command: Command) {
    this.slot = command;
  }

  buttonWasPressed() {
    this.slot?.execute();
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function garageTest() {
  const remote = new SimpleRemoteControl();       // ์ธ๋ณด์ปค
  const garageDoor = new GarageDoor();            // ๋ฆฌ์‹œ๋ฒ„

  const openCommand = new GarageDoorOpenCommand(garageDoor);      // ์ปค๋งจ๋“œ: ๋ฌธ ์—ด๊ธฐ
  const lightOnCommand = new GarageDoorLightOnCommand(garageDoor); // ์ปค๋งจ๋“œ: ๋ถˆ ์ผœ๊ธฐ

  // ์ฐจ๊ณ  ๋ฌธ ์—ด๊ธฐ
  remote.setCommand(openCommand);
  remote.buttonWasPressed(); // ์ถœ๋ ฅ: ์ฐจ๊ณ  ๋ฌธ์ด ์—ด๋ ธ์Šต๋‹ˆ๋‹ค

  // ์ฐจ๊ณ  ๋ถˆ ์ผœ๊ธฐ
  remote.setCommand(lightOnCommand);
  remote.buttonWasPressed(); // ์ถœ๋ ฅ: ์ฐจ๊ณ  ๋ถˆ์ด ์ผœ์กŒ์Šต๋‹ˆ๋‹ค
}

garageTest();

๐ŸŽฎ ์ปค๋งจ๋“œ ํŒจํ„ด์˜ ์ •์˜

์ปค๋งจ๋“œ ํŒจํ„ด(Command Pattern)์„ ์‚ฌ์šฉํ•˜๋ฉด ์š”์ฒญ ๋‚ด์—ญ์„ ๊ฐ์ฒด๋กœ ์บก์Аํ™”ํ•ด์„œ ๊ฐ์ฒด๋ฅผ ์„œ๋กœ ๋‹ค๋ฅธ ์š”์ฒญ ๋‚ด์—ญ์— ๋”ฐ๋ผ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌ๋ฉด ์š”์ฒญ์„ ํ์— ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๋กœ๊ทธ๋กœ ๊ธฐ๋กํ•˜๊ฑฐ๋‚˜ ์ž‘์—… ์ทจ์†Œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ปค๋งจ๋“œ ๊ฐ์ฒด๋Š” ์ผ๋ จ์˜ ํ–‰๋™์„ ํŠน์ • ๋ฆฌ์‹œ๋ฒ„์™€ ์—ฐ๊ฒฐ์‹œํ‚ด์œผ๋กœ์จ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์บก์Аํ™”ํ•œ ๊ฒƒ์ด๋‹ค.

์ด๋Ÿฌ๋ ค๋ฉด ํ–‰๋™๊ณผ ๋ฆฌ์‹œ๋ฒ„๋ฅผ ํ•œ ๊ฐ์ฒด์— ์ง‘์–ด๋„ฃ๊ณ  execute()๋ผ๋Š” ๋ฉ”์†Œ๋“œ ํ•˜๋‚˜๋งŒ ์™ธ๋ถ€์— ๊ณต๊ฐœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์จ์•ผ ํ•œ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ์— ์˜ํ•ด์„œ ๋ฆฌ์‹œ๋ฒ„์—์„œ ์ผ๋ จ์˜ ์ž‘์—…์ด ์ฒ˜๋ฆฌ๋œ๋‹ค. ๋ฐ–์—์„œ ๋ณผ ๋•Œ๋Š” ์–ด๋–ค ๊ฐ์ฒด๊ฐ€ ๋ฆฌ์‹œ๋ฒ„ ์—ญํ• ์„ ํ•˜๋Š”์ง€, ๊ทธ ๋ฆฌ์‹œ๋ฒ„์—์„œ ์‹ค์ œ๋กœ ์–ด๋–ค ์ผ์„ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค. execute()ย ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์š”๊ตฌ ์‚ฌํ•ญ์ด ์ฒ˜๋ฆฌ๋œ๋‹ค๋Š” ๊ฒƒ๋งŒ ์•Œ ์ˆ˜ ์žˆ์„ ๋ฟ์ด๋‹ค.

๋ช…๋ น์œผ๋กœ ๊ฐ์ฒด๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”ํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์‚ฌ๋ก€๋„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๊ฐ์ฒด๋งˆ์„ ์‹๋‹น์—์„œ๋Š” ์ข…์—…์›์ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ฃผ๋ฌธ์„œ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์—ˆ๊ณ , ๊ฐ„๋‹จํ•œ ๋ฆฌ๋ชจ์ปจ ์˜ˆ์ œ์—์„œ๋Š” ๋ฒ„ํŠผ ์Šฌ๋กฏ์— โ€˜์กฐ๋ช… ์ผœ๊ธฐโ€™ ๋ช…๋ น์„ ๋กœ๋”ฉํ–ˆ๋‹ค๊ฐ€ ๋‚˜์ค‘์— โ€˜์ฐจ๊ณ  ๋ฌธ ์—ด๊ธฐโ€™ ๋ช…๋ น์„ ๋กœ๋”ฉํ•˜๊ธฐ๋„ ํ–ˆ๋‹ค.

์•„์ง ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ์จ์„œ ํ์™€ ๋กœ๊ทธ๋ฅผ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜ ์ž‘์—… ์ทจ์†Œ๋ฅผ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฐฐ์šฐ์ง€ ๋ชปํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ธฐ๋ณธ์ ์ธ ์ปค๋งจ๋“œ ํŒจํ„ด์„ ์กฐ๊ธˆ๋งŒ ํ™•์žฅํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ธฐ๋ณธ์ ์ธ ์ปค๋งจ๋“œ ํŒจํ„ด์„ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋ฉ”ํƒ€ ์ปค๋งจ๋“œ ํŒจํ„ด(Meta Command Partten)๋„ ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฉ”ํƒ€ ์ปค๋งจ๋“œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ช…๋ น์„ ๋งคํฌ๋กœ๋กœ ํ•œ ๋ฒˆ์— ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽฎ ์ปค๋งจ๋“œ ํŒจํ„ด ํด๋ž˜์Šค ๋‹ค์ด์–ด๊ทธ๋žจ ์‚ดํŽด๋ณด๊ธฐ

Image

  • Client (ํด๋ผ์ด์–ธํŠธ)
    • ์‹ค์ œ ๋ช…๋ น์„ ๋งŒ๋“ค๊ณ  ๋ฆฌ์‹œ๋ฒ„๋ฅผ ์„ค์ •ํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
    • ์˜ˆ: โ€œ๋ถˆ ์ผœ๊ธฐโ€ ๋ช…๋ น์„ ๋งŒ๋“ค๊ณ , ์–ด๋–ค ์กฐ๋ช…์„ ์ผค์ง€ ์ง€์ •ํ•œ๋‹ค.
  • Command (๋ช…๋ น ์ธํ„ฐํŽ˜์ด์Šค)
    • ๋ชจ๋“  ๋ช…๋ น์ด ๋”ฐ๋ผ์•ผ ํ•˜๋Š” ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค๋‹ค.
    • ๋ณดํ†ตย execute()ย ๋ฉ”์„œ๋“œ๋งŒ ๊ฐ€์ง„๋‹ค.
  • ConcreteCommand (๊ตฌ์ฒด ๋ช…๋ น ๊ฐ์ฒด)
    • ์‹ค์ œ ๋ช…๋ น ๋‚ด์šฉ์ด ๋“ค์–ด ์žˆ๋Š” ํด๋ž˜์Šค๋‹ค.
    • ๋ฆฌ์‹œ๋ฒ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ ,ย execute()ย ์•ˆ์—์„œ ๋ฆฌ์‹œ๋ฒ„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
    • ์˜ˆ:ย this.light.on()์ฒ˜๋Ÿผ ์‹ค์ œ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • Receiver (๋ฆฌ์‹œ๋ฒ„)
    • ์‹ค์ œ ์ผ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ์ฒด๋‹ค.
    • ๋ช…๋ น ๊ฐ์ฒด์—์„œ ์ด ๋ฆฌ์‹œ๋ฒ„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
    • ์˜ˆ: Light, GarageDoor ๋“ฑ
  • Invoker (์ธ๋ณด์ปค)
    • ๋ช…๋ น์„ ๋ฐ›์•„ ์ €์žฅํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€, ํ•„์š”ํ•  ๋•Œย execute()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.
    • ์˜ˆ: ๋ฆฌ๋ชจ์ปจ, ๋ฒ„ํŠผ

์ปค๋งจ๋“œ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์ž‘์—…์„ ์š”๊ตฌํ•œ ์ธ๋ณด์ปค์™€ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฆฌ์‹œ๋ฒ„๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ถ„๋ฆฌ๋˜๋Š” ๊ฑธ๊นŒ?

๊ตฌ์กฐ์— ๋”ฐ๋ฅธ ์—ญํ•  ๋ถ„๋ฆฌ

๊ตฌ์„ฑ ์š”์†Œ์—ญํ• ์•Œ๊ฑฐ๋‚˜ ๋ชจ๋ฅด๋Š” ๊ฒƒ
Invoker (์˜ˆ: ๋ฆฌ๋ชจ์ปจ)๋ช…๋ น์„ ์ €์žฅํ•˜๊ณ , ์‹คํ–‰์‹œย execute()๋งŒ ํ˜ธ์ถœ๋ฆฌ์‹œ๋ฒ„๊ฐ€ ๋ญ”์ง€, ์‹ค์ œ ํ–‰๋™์ด ๋ญ”์ง€ย ๋ชจ๋ฆ„
Command (๋ช…๋ น์„œ)๋ฆฌ์‹œ๋ฒ„์™€ ํ–‰๋™์„ ๋‚ด๋ถ€์— ๋‹ด๊ณ  ์žˆ์Œexecute()ย ์•ˆ์—์„œ ๋ฆฌ์‹œ๋ฒ„์˜ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
Receiver (์˜ˆ: ์กฐ๋ช…, TV)์ง„์งœ๋กœ ์ผ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ์ฒด์‹ค์ œ ํ–‰๋™์„ ๊ตฌํ˜„
1
2
remote.setCommand(lightOnCommand); // remote๋Š” ๊ทธ๊ฒŒ ๋ญ”์ง€ ๋ชจ๋ฆ„
remote.buttonWasPressed(); // ๋‚ด๋ถ€์ ์œผ๋กœ light.on() ์‹คํ–‰๋จ
  • remote(์ธ๋ณด์ปค)๋Š” ๊ทธ๋ƒฅย execute()๋งŒ ํ˜ธ์ถœ
  • lightOnCommand(์ปค๋งจ๋“œ ๊ฐ์ฒด)๋Š” ๋‚ด๋ถ€์ ์œผ๋กœย light.on()ย ํ˜ธ์ถœ
  • light(๋ฆฌ์‹œ๋ฒ„)๊ฐ€ ์‹ค์ œ๋กœ ๋ถˆ์„ ์ผ ๋‹ค

์™œ ์ด๊ฒŒ ์ข‹์„๊นŒ?

  • ์ธ๋ณด์ปค๋Š”ย ๋ชจ๋“ˆํ™”, ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ๋ฆฌ์‹œ๋ฒ„๋Š”ย ๋™์ž‘์—๋งŒ ์ง‘์ค‘
  • ์ปค๋งจ๋“œ๋ฅผ ๋ฐ”๊ฟ” ๋ผ์šฐ๋ฉดย ๋™์ž‘์„ ์œ ์—ฐํ•˜๊ฒŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ

์ฆ‰, ์ปค๋งจ๋“œ ํŒจํ„ด์€ ์ค‘๊ฐ„์—ย ๋ช…๋ น ๊ฐ์ฒด๋ฅผ ๋ผ์›Œ ๋„ฃ์–ด โ€œ๋ˆ„๊ฐ€ ๋ช…๋ นํ–ˆ๊ณ , ๋ˆ„๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€โ€๋ฅผ ๋А์Šจํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒŒ ํ•ต์‹ฌ์ด๋‹ค.

๐ŸŽฎ ์Šฌ๋กฏ์— ๋ช…๋ น ํ• ๋‹นํ•˜๊ธฐ

Image

  • ๊ฐ ์Šฌ๋กฏ๋งˆ๋‹ค ์ปค๋งจ๋“œ ๊ฐ์ฒด๊ฐ€ ํ• ๋‹น๋œ๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ•ด๋‹น ์ปค๋งจ๋“œ ๊ฐ์ฒด์˜ execute() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
  • execute() ๋ฉ”์†Œ๋“œ์—์„œ๋Š” ๋ฆฌ์‹œ๋ฒ„๋กœ ํ•˜์—ฌ๊ธˆ ํŠน์ • ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์ง€์‹œํ•œ๋‹ค.

๐ŸŽฎย ๋ฆฌ๋ชจ์ปจ ์ฝ”๋“œ ๋งŒ๋“ค๊ธฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// ์ปค๋งจ๋“œ ์ธํ„ฐํŽ˜์ด์Šค
interface Command {
  execute(): void;
}

// ์•„๋ฌด ๋™์ž‘๋„ ํ•˜์ง€ ์•Š๋Š” ๊ธฐ๋ณธ ์ปค๋งจ๋“œ (Null Object ํŒจํ„ด)
class NoCommand implements Command {
  execute() {
    // ์•„๋ฌด ์ผ๋„ ํ•˜์ง€ ์•Š์Œ
  }
}

// ์ธ๋ณด์ปค ์—ญํ• ์˜ ๋ฆฌ๋ชจ์ปจ ํด๋ž˜์Šค
class RemoteControl {
  private static readonly SLOT_SIZE = 7; // ์Šฌ๋กฏ ๊ฐœ์ˆ˜: 7๊ฐœ
  private onCommands: Command[];         // ๊ฐ ์Šฌ๋กฏ์˜ ON ์ปค๋งจ๋“œ ๋ฐฐ์—ด
  private offCommands: Command[];        // ๊ฐ ์Šฌ๋กฏ์˜ OFF ์ปค๋งจ๋“œ ๋ฐฐ์—ด

  constructor() {
    const noCommand = new NoCommand(); // ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋„ฃ์„ ๋ช…๋ น

    // ๋ชจ๋“  ์Šฌ๋กฏ์„ NoCommand๋กœ ์ดˆ๊ธฐํ™”
    this.onCommands = new Array(RemoteControl.SLOT_SIZE).fill(noCommand);
    this.offCommands = new Array(RemoteControl.SLOT_SIZE).fill(noCommand);
  }

  // ์Šฌ๋กฏ ๋ฒˆํ˜ธ์— ON/OFF ๋ช…๋ น์„ ๋“ฑ๋กํ•˜๋Š” ๋ฉ”์„œ๋“œ
  setCommand(slot: number, onCommand: Command, offCommand: Command) {
    this.onCommands[slot] = onCommand;
    this.offCommands[slot] = offCommand;
  }

  // ON ๋ฒ„ํŠผ ๋ˆŒ๋ €์„ ๋•Œ ์‹คํ–‰๋˜๋Š” ๋ฉ”์„œ๋“œ
  onButtonWasPushed(slot: number) {
    this.onCommands[slot].execute();
  }

  // OFF ๋ฒ„ํŠผ ๋ˆŒ๋ €์„ ๋•Œ ์‹คํ–‰๋˜๋Š” ๋ฉ”์„œ๋“œ
  offButtonWasPushed(slot: number) {
    this.offCommands[slot].execute();
  }

  // ํ˜„์žฌ ๋ฆฌ๋ชจ์ปจ์— ์„ค์ •๋œ ๋ช…๋ น ๋ชฉ๋ก์„ ๋ฌธ์ž์—ด๋กœ ์ถœ๋ ฅ
  toString(): string {
    let result = "\n------ Remote Control -------\n";
    for (let i = 0; i < RemoteControl.SLOT_SIZE; i++) {
      result += `[slot ${i}] ${this.onCommands[i].constructor.name}    ${this.offCommands[i].constructor.name}\n`;
    }
    return result;
  }
}

  • ์ „์ฒด ์Šฌ๋กฏ ์ˆ˜๋Š” 7๊ฐœ๋กœ ๊ณ ์ •๋˜์–ด ์žˆ๋‹ค.
  • on, off ๋ช…๋ น์„ ๊ฐ๊ฐ ๋ฐฐ์—ด๋กœ ์ €์žฅํ•œ๋‹ค.
  • ์ดˆ๊ธฐ์—๋Š” ๋ชจ๋“  ์Šฌ๋กฏ์— ์•„๋ฌด ๋™์ž‘๋„ ํ•˜์ง€ ์•Š๋Š” NoCommand ๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด๋‘”๋‹ค
  • setCommand๋กœ ํŠน์ • ์Šฌ๋กฏ์— on๊ณผ off ๋ช…๋ น์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค
  • onButtonWasPushed๋Š” ํ•ด๋‹น ์Šฌ๋กฏ์˜ on ๋ช…๋ น์„ ์‹คํ–‰ํ•œ๋‹ค
  • offButtonWasPushed๋Š” ํ•ด๋‹น ์Šฌ๋กฏ์˜ off ๋ช…๋ น์„ ์‹คํ–‰ํ•œ๋‹ค
  • toString ๋ฉ”์„œ๋“œ๋Š” ํ˜„์žฌ ์Šฌ๋กฏ์— ์–ด๋–ค ๋ช…๋ น๋“ค์ด ๋“ค์–ด์žˆ๋Š”์ง€ ๋ฌธ์ž์—ด๋กœ ์ถœ๋ ฅํ•œ๋‹ค

๐ŸŽฎย ์ปค๋งจ๋“œ ํด๋ž˜์Šค ๋งŒ๋“ค๊ธฐ

์•ž์—์„œ SimpleRemoteControl์„ ๋งŒ๋“ค ๋•Œ LightOnCommand๋ผ๋Š” ์ปค๋งจ๋“œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“  ์ ์ด ์žˆ๋‹ค. ๊ทธ ์ฝ”๋“œ๋ฅผ ์—ฌ๊ธฐ์— ๊ทธ๋Œ€๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค. ์กฐ๋ช…์„ ๋Œ ๋•Œ ์“ฐ๋Š” LightOffCommand๋ผ๋Š” ์ปค๋งจ๋“œ ํด๋ž˜์Šค๋„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค.

1
2
3
4
5
6
7
class LightOffCommand implements Command {
  constructor(private light: OutdoorLight) {}

  execute() {
    this.light.off()
  }
}

์˜ค๋””์˜ค๋ฅผ ์ผœ๊ณ  ๋Œ ๋•Œ ์‚ฌ์šฉํ•  ์ปค๋งจ๋“œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์ž. ๋„๋Š” ๊ฑด off() ๋ฉ”์†Œ๋“œ์™€ ์—ฐ๊ฒฐํ•ด ์ฃผ๋ฉด ๋˜์ง€๋งŒ, ์ผœ๋Š” ๊ฑด ์กฐ๊ธˆ ๋” ์–ด๋ ต๋‹ค. ์ผ๋‹จ ์˜ค๋””์˜ค๋ฅผ ์ผค ๋•Œ ์ž๋™์œผ๋กœ CD๊ฐ€ ์žฌ์ƒ๋˜๋„๋ก ํ•˜๋Š” stereoOnWithCDCommand ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋ณด์ž.

1
2
3
4
5
6
7
8
9
class StereoOnWithCDCommand implements Command {
  constructor(private stereo: Stereo) {}

  execute() {
    this.stereo.on();
    this.stereo.setCd();
    this.stereo.setVolume(11);
  }
}

๐ŸŽฎย ๋ฆฌ๋ชจ์ปจ ํ…Œ์ŠคํŠธ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function RemoteLoader() {
  const remoteControl = new RemoteControl();

  const livingRoomLight = new Light("๊ฑฐ์‹ค");
  const kitchenLight = new Light("์ฃผ๋ฐฉ");
  const ceilingFan = new CeilingFan("๊ฑฐ์‹ค");
  const garageDoor = new GarageDoor("์ฐจ๊ณ ");
  const stereo = new Stereo("๊ฑฐ์‹ค");

  const livingRoomLightOn = new LightOnCommand(livingRoomLight);
  const livingRoomLightOff = new LightOffCommand(livingRoomLight);
  const kitchenLightOn = new LightOnCommand(kitchenLight);
  const kitchenLightOff = new LightOffCommand(kitchenLight);

  const ceilingFanOn = new CeilingFanOnCommand(ceilingFan);
  const ceilingFanOff = new CeilingFanOffCommand(ceilingFan);

  const garageDoorUp = new GarageDoorUpCommand(garageDoor);
  const garageDoorDown = new GarageDoorDownCommand(garageDoor);

  const stereoOnWithCD = new StereoOnWithCDCommand(stereo);
  const stereoOff = new StereoOffCommand(stereo);

  remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
  remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);
  remoteControl.setCommand(2, ceilingFanOn, ceilingFanOff);
  remoteControl.setCommand(3, stereoOnWithCD, stereoOff);

  console.log(remoteControl.toString());

  remoteControl.onButtonWasPushed(0);
  remoteControl.offButtonWasPushed(0);
  remoteControl.onButtonWasPushed(1);
  remoteControl.offButtonWasPushed(1);
  remoteControl.onButtonWasPushed(2);
  remoteControl.offButtonWasPushed(2);
  remoteControl.onButtonWasPushed(3);
  remoteControl.offButtonWasPushed(3);
}

RemoteLoader();

4๋ฒˆ๋ถ€ํ„ฐ 6๋ฒˆ ์Šฌ๋กฏ๊นŒ์ง€๋Š” NoCommand๋ผ๊ณ  ๋‚˜์˜ค๋Š”๋ฐ ๊ทธ๊ฑด ๋ญ˜๊นŒ?

  • NoCommand ๊ฐ์ฒด
    • NoCommand ๊ฐ์ฒด๋Š” ์ผ์ข…์˜ ๋„ ๊ฐ์ฒด์ด๋‹ค. ๋”ฑํžˆ ๋ฆฌํ„ดํ•  ๊ฐ์ฒด๋Š” ์—†์ง€๋งŒ ํด๋ผ์ด์–ธํŠธ ์ชฝ์—์„œ null์„ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์•„๋„ ๋˜๋„๋ก ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๋„ ๊ฐ์ฒด๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ข‹๋‹ค. ํŠน์ • ์Šฌ๋กฏ์„ ์“ฐ๋ ค๊ณ  ํ•  ๋•Œ ๋งˆ๋‹ค ๊ฑฐ๊ธฐ์— ๋ญ”๊ฐ€๊ฐ€ ๋กœ๋”ฉ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ์ข€ ๊ท€์ฐฎ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๐ŸŽฎย API ๋ฌธ์„œ ๋งŒ๋“ค๊ธฐ

Image

  • Command
    • ๋ชจ๋“  RemoteControl ํด๋ž˜์Šค์šฉ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋Š” Command๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.
    • ์ปค๋งจ๋“œ ๊ฐ์ฒด๋Š” ์ผ๋ จ์˜ ํ–‰๋™์„ ์บก์Аํ™”ํ•˜๋ฉฐ, ๋ฆฌ๋ชจ์ฝ˜์€ ํ•ด๋‹น ํ–‰๋™์„ execute(), undo()๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœํ•œ๋‹ค.
  • LightOnCommand, LightOffCommand
    • ๋ฆฌ๋ชจ์ฝ˜์„ ๋ˆŒ๋ €์„๋•Œ ํ˜ธ์ถœ๋˜๋Š” ํ–‰๋™์ด๋‹ค. Command ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋กœ ๊ตฌํ˜„๋œ๋‹ค.
    • ์ปค๋งจ๋“œ ๊ฐ์ฒด์—๋Š” ์—…์ฒด์—์„œ ์ œ๊ณตํ•œ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค์˜ ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ์กด์žฌํ•˜์—ฌ, execute()-undo()๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.
  • RemoteControl
    • ๋ฒ„ํŠผ๋งˆ๋‹ค ํ•˜๋‚˜์˜ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ํ• ๋‹นํ•ด์„œ ๊ด€๋ฆฌํ•œ๋‹ค.
    • ๋ฒ„ํŠผ์ด ๋ˆŒ๋ฆฌ๋ฉด ๋ฒ„ํŠผ์— ํ•ด๋‹นํ•˜๋Š” ButtonWasPushed()๊ฐ€ ํ˜ธ์ถœ๋˜์–ด execute()๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
  • Light
    • ํ˜‘๋ ฅ์—…์ฒด๊ฐ€ ์ œ๊ณตํ•œ ํด๋ž˜์Šค๋กœ, Light ํด๋ž˜์Šค๋ฅผ ์˜ˆ๋กœ ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
  • RemoteLoader
    • ๋ฆฌ๋ชจ์ฝ˜ ์Šฌ๋กฏ์— ๋กœ๋”ฉ๋˜๋Š” ์ผ๋ จ์˜ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
    • ๊ฐ ์ปค๋งจ๋“œ ๊ฐ์ฒด์—๋Š” ํ™ˆ ์˜คํ† ๋ฉ”์ด์…˜ ์žฅ์น˜๋กœ ์ „์†ก๋˜๋Š” ์š”์ฒญ์ด ์บก์Аํ™”๋˜์–ด ์žˆ๋‹ค.

๐ŸŽฎย ์ž‘์—… ์ทจ์†Œ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ํ•˜๊ธฐ

๋ฆฌ๋ชจ์ปจ์— ์ž‘์—…์„ ์ทจ์†Œํ•˜๋Š” UNDO ๋ฒ„ํŠผ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค. ๋” ๋ณต์žกํ•œ ์˜ˆ๋ฅผ ์‚ดํŽด๋ณด๊ธฐ ์ „์— ์šฐ์„  ์กฐ๋ช… ์ž‘์—… ์ทจ์†Œ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด ๋ณด์ž.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
interface Command {
  execute(): void;
  undo(): void;
}

class LightOnCommand implements Command {
  constructor(private light: Light) {}

  execute() {
    this.light.on();
  }

  undo() {
    this.light.off(); // ์ด์ „ ์ƒํƒœ๋กœ ๋˜๋Œ๋ฆฌ๊ธฐ
  }
}

class LightOffCommand implements Command {
  constructor(private light: Light) {}

  execute() {
    this.light.off();
  }

  undo() {
    this.light.on(); // ์ด์ „ ์ƒํƒœ๋กœ ๋˜๋Œ๋ฆฌ๊ธฐ
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class RemoteControl {
  private static readonly SLOT_SIZE = 7;
  private onCommands: Command[];
  private offCommands: Command[];
  private undoCommand: Command;

  constructor() {
    const noCommand = new NoCommand();
    this.onCommands = new Array(RemoteControl.SLOT_SIZE).fill(noCommand);
    this.offCommands = new Array(RemoteControl.SLOT_SIZE).fill(noCommand);
    this.undoCommand = noCommand;
  }

  setCommand(slot: number, onCommand: Command, offCommand: Command) {
    this.onCommands[slot] = onCommand;
    this.offCommands[slot] = offCommand;
  }

  onButtonWasPushed(slot: number) {
    this.onCommands[slot].execute();
    this.undoCommand = this.onCommands[slot];
  }

  offButtonWasPushed(slot: number) {
    this.offCommands[slot].execute();
    this.undoCommand = this.offCommands[slot];
  }

  undoButtonWasPushed() {
    this.undoCommand.undo();
  }
}

๐ŸŽฎย ์ž‘์—… ์ทจ์†Œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ๋•Œ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

Light ํด๋ž˜์Šค์˜ ์ž‘์—… ์ทจ์†Œ ๊ธฐ๋Šฅ์„ ๋ฐฐ์› ๋Š”๋ฐ, ์ž‘์—… ์ทจ์†Œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋‹ค ๋ณด๋ฉด ๊ฐ„๋‹จํ•œ ์ƒํƒœ๋ฅผ ์ €์žฅํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ๋„ ์ข…์ข… ์ƒ๊ธด๋‹ค. ์„ ํ’๊ธฐ ์ œ์กฐ ์—…์ฒด์—์„œ ์ œ๊ณตํ•œ CeilingFan ํด๋ž˜์Šค๋กœ ๊ฐ„๋‹จํ•œ ์ƒํƒœ๋ฅผ ์ €์žฅํ•ด ๋ณด์ž. ์„ ํ’๊ธฐ๋Š” ์†๋„๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์•Œ์•„๋‘์ž.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class CeilingFan {
  static readonly HIGH = 3;
  static readonly MEDIUM = 2;
  static readonly LOW = 1;
  static readonly OFF = 0;

  private speed: number;
  
  constructor(private location: string) {
    this.speed = CeilingFan.OFF;
  }

  high() {
    this.speed = CeilingFan.HIGH;
    console.log(`${this.location} ceiling fan is on high`);
  }

  medium() {
    this.speed = CeilingFan.MEDIUM;
    console.log(`${this.location} ceiling fan is on medium`);
  }

  low() {
    this.speed = CeilingFan.LOW;
    console.log(`${this.location} ceiling fan is on low`);
  }

  off() {
    this.speed = CeilingFan.OFF;
    console.log(`${this.location} ceiling fan is off`);
  }

  getSpeed(): number {
    return this.speed;
  }
}

๐ŸŽฎย ์„ ํ’๊ธฐ ๋ช…๋ น์–ด์— ์ž‘์—… ์ทจ์†Œ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ํ•˜๊ธฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class CeilingFanHighCommand implements Command {
  private prevSpeed: number;

  constructor(private ceilingFan: CeilingFan) {
    this.prevSpeed = CeilingFan.OFF;
  }

  execute() {
    this.prevSpeed = this.ceilingFan.getSpeed(); // ์‹คํ–‰ ์ „ ์ƒํƒœ ์ €์žฅ
    this.ceilingFan.high();                      // ํ˜„์žฌ ํ–‰๋™ ์‹คํ–‰
  }

  undo() {
    // ์ด์ „ ์†๋„ ์ƒํƒœ๋กœ ๋˜๋Œ๋ฆฌ๊ธฐ
    switch (this.prevSpeed) {
      case CeilingFan.HIGH:
        this.ceilingFan.high();
        break;
      case CeilingFan.MEDIUM:
        this.ceilingFan.medium();
        break;
      case CeilingFan.LOW:
        this.ceilingFan.low();
        break;
      default:
        this.ceilingFan.off();
    }
  }
}

๐ŸŽฎย ์„ ํ’๊ธฐ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋งŒ๋“ค๊ธฐ

๋ฆฌ๋ชจ์ปจ์— ์„ ํ’๊ธฐ์šฉ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ๋„ฃ์–ด ํ…Œ์ŠคํŠธํ•ด ๋ณผ ๋•Œ๊ฐ€ ๋˜์—ˆ๋‹ค. 0๋ฒˆ ์Šฌ๋กฏ์˜ ON ๋ฒ„ํŠผ์— ์„ ํ’๊ธฐ ์†๋„๋ฅผ MEDIUM์œผ๋กœ ์„ค์ •ํ•˜๋Š” ๊ธฐ๋Šฅ์„, 1๋ฒˆ ์Šฌ๋กฏ์˜ ON ๋ฒ„ํŠผ์— ์„ ํ’๊ธฐ ์†๋„๋ฅผ HIGH๋กœ ์„ค์ •ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ• ๋‹นํ•  ๊ฒƒ์ด๋‹ค. OFF ๋ฒ„ํŠผ์—๋Š” ์†๋„๋ฅผ OFF๋กœ ์„ค์ •ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ• ๋‹นํ•  ๊ฒƒ์ด๋‹ค.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function RemoteLoader() {
  const remoteControl = new RemoteControl();         // ์ธ๋ณด์ปค
  const ceilingFan = new CeilingFan("๊ฑฐ์‹ค");          // ๋ฆฌ์‹œ๋ฒ„

  // ์ปค๋งจ๋“œ ๊ฐ์ฒด ์ƒ์„ฑ
  const ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan);
  const ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);
  const ceilingFanOff = new CeilingFanOffCommand(ceilingFan);

  // ์Šฌ๋กฏ ์„ค์ •
  remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff); // 0๋ฒˆ ์Šฌ๋กฏ: MEDIUM โ†” OFF
  remoteControl.setCommand(1, ceilingFanHigh, ceilingFanOff);   // 1๋ฒˆ ์Šฌ๋กฏ: HIGH โ†” OFF

  // ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค
  remoteControl.onButtonWasPushed(0);  // ๊ฑฐ์‹ค ์„ ํ’๊ธฐ MEDIUM ์„ค์ •
  remoteControl.offButtonWasPushed(0); // ๊ฑฐ์‹ค ์„ ํ’๊ธฐ OFF
  remoteControl.undoButtonWasPushed(); // ์ด์ „ ์ƒํƒœ(MEDIUM) ๋ณต์›

  remoteControl.onButtonWasPushed(1);  // ๊ฑฐ์‹ค ์„ ํ’๊ธฐ HIGH ์„ค์ •
  remoteControl.undoButtonWasPushed(); // ์ด์ „ ์ƒํƒœ(OFF) ๋ณต์›
}

๐ŸŽฎย ์—ฌ๋Ÿฌ ๋™์ž‘์„ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๊ธฐ

๋ฒ„ํŠผ ํ•œ ๊ฐœ๋งŒ ๋ˆ„๋ฅด๋ฉด ์กฐ๋ช…์ด ์–ด๋‘์–ด์ค˜์ง€๋ฉด์„œ ์˜ค๋””์˜ค์™€ TV๊ฐ€ ์ผœ์ง€๊ณ , DVD ๋ชจ๋“œ๋กœ ๋ณ€๊ฒฝ๋˜๊ณ , ์š•์กฐ์— ๋ฌผ์ด ์ฑ„์›Œ์ง€๋Š” ๊ฒƒ๊นŒ์ง€ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ์–ด์•ผ ์ง„์ •ํ•œ ๋ฆฌ๋ชจ์ปจ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MacroCommand implements Command {
  constructor(private commands: Command[]) {}

  execute() {
    for (const command of this.commands) {
      command.execute();
    }
  }

  undo() {
    // ์—ญ์ˆœ์œผ๋กœ undo ์‹คํ–‰
    for (let i = this.commands.length - 1; i >= 0; i--) {
      this.commands[i].undo();
    }
  }
}

๐ŸŽฎย ๋งคํฌ๋กœ ์ปค๋งจ๋“œ ์‚ฌ์šฉํ•˜๊ธฐ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function RemoteLoader() {
  const remoteControl = new RemoteControl(); // ์ธ๋ณด์ปค

  const light = new Light("Living Room");    // ๋ฆฌ์‹œ๋ฒ„ 1
  const stereo = new Stereo("Living Room");  // ๋ฆฌ์‹œ๋ฒ„ 2

  const lightOnCommand = new LightOnCommand(light);
  const lightOffCommand = new LightOffCommand(light);
  const stereoOnCommand = new StereoOnWithCDCommand(stereo);
  const stereoOffCommand = new StereoOffCommand(stereo);

  const partyOn: Command[] = [lightOnCommand, stereoOnCommand];
  const partyOff: Command[] = [lightOffCommand, stereoOffCommand];

  const partyOnMacro = new MacroCommand(partyOn);
  const partyOffMacro = new MacroCommand(partyOff);

  remoteControl.setCommand(0, partyOnMacro, partyOffMacro);

  console.log(remoteControl.toString());

  console.log("---- macro on ------");
  remoteControl.onButtonWasPushed(0);

  console.log("---- macro off ------");
  remoteControl.offButtonWasPushed(0);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
------ Remote Control -------
[slot 0] MacroCommand    MacroCommand
[slot 1] NoCommand    NoCommand
[slot 2] NoCommand    NoCommand
[slot 3] NoCommand    NoCommand
[slot 4] NoCommand    NoCommand
[slot 5] NoCommand    NoCommand
[slot 6] NoCommand    NoCommand
---- macro on ------
Living Room light is on
Living Room stereo is on
CD๊ฐ€ ์žฌ์ƒ๋ฉ๋‹ˆ๋‹ค
๋ณผ๋ฅจ์ด 11๋กœ ์„ค์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค
---- macro off ------
Living Room light is off
Living Room stereo is off
  1. ์ปค๋งจ๋“œ ๊ฐ์ฒด๋Š” ํ•ญ์ƒ ๋ฆฌ์‹œ๋ฒ„๊ฐ€ ํ•„์š”ํ• ๊นŒ?
    • ๊ผญ ๊ทธ๋Ÿฐ ๊ฑด ์•„๋‹ˆ๋‹ค. ์ปค๋งจ๋“œ ๊ฐ์ฒด ์ž์ฒด์—์„œ ์‹คํ–‰ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋Š”ย โ€˜์Šค๋งˆํŠธ ์ปค๋งจ๋“œโ€™ย ๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค.
    • ํ•˜์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ๋ฆฌ์‹œ๋ฒ„์— ์žˆ๋Š” ํ–‰๋™์„ ๋‹จ์ˆœํžˆ ํ˜ธ์ถœํ•˜๋Š”ย โ€˜๋”๋ฏธ ์ปค๋งจ๋“œโ€™ย ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    • ์ด์œ ๋Š” ๋ช…๋ น๊ณผ ์‹ค์ œ ์ž‘์—…์„ ๋ถ„๋ฆฌํ•˜๊ณ ,ย ์ธ๋ณด์ปค์™€ ๋ฆฌ์‹œ๋ฒ„๋ฅผ ๋А์Šจํ•˜๊ฒŒ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋‹ค.
    • ์ปค๋งจ๋“œ ์•ˆ์—์„œ ๋‹ค ์ฒ˜๋ฆฌํ•˜๋ฉด ๋‚˜์ค‘์—ย ์œ ์—ฐ์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.
  2. Undo(์ž‘์—… ์ทจ์†Œ)๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด?
    • ๋‹จ์ˆœํžˆ ๋งˆ์ง€๋ง‰ ์ปค๋งจ๋“œ ํ•˜๋‚˜๋งŒ ๊ธฐ์–ตํ•˜๋Š” ๋Œ€์‹ ,ย ์‹คํ–‰ํ•œ ์ปค๋งจ๋“œ๋“ค์„ ์Šคํƒ์— ์Œ“์•„๋‘๋ฉด ๋œ๋‹ค.
    • ์‚ฌ์šฉ์ž๊ฐ€ Undo ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ๋•Œ๋งˆ๋‹ค ์Šคํƒ์—์„œย ๊ฐ€์žฅ ์ตœ๊ทผ ์ปค๋งจ๋“œ๋ฅผ ๊บผ๋‚ด์„œ undo()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋œ๋‹ค.
    • ์ฆ‰,ย ํžˆ์Šคํ† ๋ฆฌ ์Šคํƒ์„ ์ด์šฉํ•ด ์—ฌ๋Ÿฌ ๋‹จ๊ณ„ undo๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ํŒŒํ‹ฐ ๋ชจ๋“œ ๊ฐ™์€ ๋งคํฌ๋กœ ๊ธฐ๋Šฅ์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋„ ๋ ๊นŒ?
    • ๋ฌผ๋ก  ๊ฐ€๋Šฅํ•˜์ง€๋งŒ,ย PartyCommand ์•ˆ์— ๋ชจ๋“  ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ๋„ฃ๋Š” ๋ฐฉ์‹์€ ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.
    • ๋Œ€์‹ ย MacroCommand๋ฅผ ์‚ฌ์šฉํ•˜๋ฉดย ์—ฌ๋Ÿฌ ์ปค๋งจ๋“œ๋ฅผ ๋ฌถ์–ด์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ณ ,
    • ๋‚˜์ค‘์— ๋ณ€๊ฒฝ์ด๋‚˜ ํ™•์žฅํ•  ๋•Œ๋„ ๋” ๊น”๋”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๊ฒฐ๋ก : ์ง์ ‘ ์ฒ˜๋ฆฌ๋ณด๋‹คย MacroCommandย ๋ฐฉ์‹์ดย ํ™•์žฅ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜ ์ธก๋ฉด์—์„œ ํ›จ์”ฌ ๋‚ซ๋‹ค.

๐ŸŽฎย ์ปค๋งจ๋“œ ํŒจํ„ด ํ™œ์šฉํ•˜๊ธฐ

์ปค๋งจ๋“œ ํŒจํ„ด์„ ํ™œ์šฉํ•˜๋ฉดย ์ปดํ“จํ…Œ์ด์…˜์˜ ์ผ๋ถ€๋ถ„(๋ฆฌ์‹œ๋ฒ„ + ํ–‰๋™)ย ์„ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ์บก์Аํ™”ํ•ด์„œ, ๊ทธ ๊ฐ์ฒด๋ฅผย ์ผ๊ธ‰ ๊ฐ์ฒด์ฒ˜๋Ÿผ ์ „๋‹ฌํ•˜๊ฑฐ๋‚˜ย ๋‚˜์ค‘์— ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰, ํด๋ผ์ด์–ธํŠธ์—์„œ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ๋†“๊ณ ย ์˜ค๋žœ ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„์—๋„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.

์ด๋Ÿฌํ•œ ํŠน์„ฑ์„ ํ™œ์šฉํ•˜๋ฉด ์ปค๋งจ๋“œ ํŒจํ„ด์„ย ์Šค์ผ€์ค„๋Ÿฌ,ย ์Šค๋ ˆ๋“œ ํ’€,ย ์ž‘์—… ํย ๊ฐ™์€ ๊ตฌ์กฐ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Image

์ž‘์—… ํ ๊ตฌ์กฐ ์˜ˆ์‹œ

  1. ์ปค๋งจ๋“œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ํ์— ๋„ฃ๋Š”๋‹ค.
  2. ํ์˜ ํ•œ์ชฝ ๋์—๋Š”ย ์ž‘์—…์„ ๋“ฑ๋กํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์žˆ๊ณ ,
  3. ๋ฐ˜๋Œ€์ชฝ ๋์—๋Š”ย ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์Šค๋ ˆ๋“œ๋“ค์ด ๋Œ€๊ธฐ ์ค‘์ด๋‹ค.
  4. ์Šค๋ ˆ๋“œ๋Š” ํ์—์„œ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ๊บผ๋‚ธ ํ›„,ย execute() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.
  5. ์ž‘์—…์ด ๋๋‚˜๋ฉด ํ•ด๋‹น ์ปค๋งจ๋“œ ๊ฐ์ฒด๋Š” ๋ฒ„๋ ค์ง€๊ณ , ๋‹ค์Œ ์ปค๋งจ๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.

์™œ ์ด ๊ตฌ์กฐ๊ฐ€ ์œ ์šฉํ• ๊นŒ?

  • ์ž‘์—… ํ๋Š” ์‹ค์ œ ์ž‘์—… ๋‚ด์šฉ(๊ณ„์‚ฐ, ๋‹ค์šด๋กœ๋“œ ๋“ฑ)์„ ์•Œ ํ•„์š”๊ฐ€ ์—†๋‹ค.
  • ๊ทธ์ € ์ปค๋งจ๋“œ ๊ฐ์ฒด๋งŒ ํ์— ๋“ค์–ด์˜ค๋ฉด ์Šค๋ ˆ๋“œ๊ฐ€ ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค.
  • ์˜ˆ๋ฅผ ๋“ค์–ด, ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ย ๊ธˆ์œต ๊ณ„์‚ฐ์„ ํ•˜๋‹ค๊ฐ€, ๋‹ค์Œ์—”ย ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
  • ์ž‘์—… ํ๋Š”ย ์˜ค์ง ์ปค๋งจ๋“œ ๊ฐ์ฒด์˜ execute()๋งŒ ํ˜ธ์ถœํ•  ๋ฟ์ด๋ฏ€๋กœ,

    ์ž‘์—…์˜ ์ข…๋ฅ˜์— ์ „ํ˜€ ์˜์กดํ•˜์ง€ ์•Š๋Š”ย ๋А์Šจํ•œ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

์š”์•ฝ

  • ์ปค๋งจ๋“œ ๊ฐ์ฒด๋Š”ย ์ž‘์—… ๋‹จ์œ„๋ฅผ ์ถ”์ƒํ™”ํ•œ ๊ฐ์ฒด์ด๋‹ค.
  • ์ด ๊ฐ์ฒด๋ฅผ ํ์— ๋‹ด๊ณ ,ย ๋‚˜์ค‘์— ํ•„์š”ํ•  ๋•Œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด๋Ÿฐ ๊ตฌ์กฐ๋Š”ย ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ,ย ์Šค๋ ˆ๋“œ ๋ถ„๋ฆฌ,ย ์œ ์—ฐํ•œ ์ž‘์—… ๊ด€๋ฆฌย ๋“ฑ์— ๋งค์šฐ ํšจ๊ณผ์ ์ด๋‹ค.

๐ŸŽฎย ์ปค๋งจ๋“œ ํŒจํ„ด ๋” ํ™œ์šฉํ•˜๊ธฐ

์ผ๋ถ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ย ์‚ฌ์šฉ์ž์˜ ๋ชจ๋“  ํ–‰๋™์„ ๊ธฐ๋กํ•ด๋‘์—ˆ๋‹ค๊ฐ€, ์•ฑ์ด ์ค‘๋‹จ๋˜๊ฑฐ๋‚˜ ์‹œ์Šคํ…œ์ด ๋‹ค์šด๋˜์—ˆ์„ ๋•Œย ์ด๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•ด ๋ณต๊ตฌํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.

์ด๋•Œ ์ปค๋งจ๋“œ ํŒจํ„ด์„ ํ™œ์šฉํ•˜๋ฉด ํ–‰๋™ ํ•˜๋‚˜ํ•˜๋‚˜๋ฅผย ๊ฐ์ฒด๋กœ ์ €์žฅํ•˜๊ณ , ํ•„์š”ํ•  ๋•Œ ๋‹ค์‹œย ์‹คํ–‰ (execute())ย ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณต๊ตฌ ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•˜๊ธฐ์— ์ ํ•ฉํ•˜๋‹ค.

์ปค๋งจ๋“œ ํŒจํ„ด์„ ํ™œ์šฉํ•œ ๋กœ๊ทธ ๊ธฐ๋ก ๊ตฌ์กฐ

  • ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ๋””์Šคํฌ์— ์ €์žฅํ•œ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ข…๋ฃŒ๋˜๊ฑฐ๋‚˜ ๋‹ค์šด๋œ ํ›„ ์žฌ์‹œ์ž‘๋˜๋ฉด,

    ์ €์žฅ๋œ ์ปค๋งจ๋“œ๋ฅผ ๋‹ค์‹œ ๋ถˆ๋Ÿฌ์™€ย execute()๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•œ๋‹ค.

  • ์ด ๋ฐฉ์‹์œผ๋กœย ์‹œ์Šคํ…œ์„ ๋งˆ์ง€๋ง‰ ์ฒดํฌํฌ์ธํŠธ ์ดํ›„ ์ƒํƒœ๋กœ ๋ณต์›ํ•  ์ˆ˜ ์žˆ๋‹ค.

Java์—์„œ๋Š” ์ปค๋งจ๋“œ ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ™”ํ•ด ์ €์žฅํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ง๋ ฌํ™”๋Š” ์ œ์•ฝ์ด ๋งŽ๊ณ  ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ์™ธ: ๋‹จ์ˆœํ•œ ๋ฆฌ๋ชจ์ปจ์—๋Š” ๋ถˆํ•„์š”ํ•œ ๊ธฐ๋Šฅ

  • ๋ฆฌ๋ชจ์ปจ ์˜ˆ์ œ์ฒ˜๋Ÿผ ๋‹จ์ˆœํ•œ ์ƒํƒœ ์กฐ์ž‘๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ์—”ย ๋กœ๊ทธ ๊ธฐ๋ก์ด ํฐ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค.
  • ํ•˜์ง€๋งŒย ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃจ๊ฑฐ๋‚˜,ย ์ค‘๊ฐ„ ์ €์žฅ์ด ์–ด๋ ค์šด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—๋Š” ๋งค์šฐ ์œ ์šฉํ•˜๋‹ค.

์˜ˆ์‹œ: ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜

  • ๋งค๋ฒˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜์ง€ ์•Š๊ณ ,
  • ํŠน์ • ์ฒดํฌํฌ์ธํŠธ ์ดํ›„์˜ ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ž‘์—…์„ ์ปค๋งจ๋“œ ๊ฐ์ฒด๋กœ ๊ธฐ๋กํ•œ๋‹ค.
  • ๋ณต๊ตฌ ์‹œ,ย ๊ธฐ๋ก๋œ ์ปค๋งจ๋“œ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฉด ์ฒดํฌํฌ์ธํŠธ ์ดํ›„์˜ ์ƒํƒœ๋ฅผ ๋˜์‚ด๋ฆด ์ˆ˜ ์žˆ๋‹ค.

ํ™•์žฅ ๊ฐ€๋Šฅ์„ฑ: ํŠธ๋žœ์žญ์…˜ ์ ์šฉ

  • ๋” ๋ณต์žกํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ์ด ๊ตฌ์กฐ๋ฅผย ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„๋กœ ๋ฌถ์–ด,
    • ๋ชจ๋“  ์ž‘์—…์ดย ์™„์ „ํžˆ ์ ์šฉ๋˜๊ฑฐ๋‚˜
    • ์ „๋ถ€ ์ทจ์†Œ(rollback)ย ๋˜๋„๋ก ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค.
  • ์ฆ‰, ์ปค๋งจ๋“œ ํŒจํ„ด์€ย ๋กœ๊ทธ ์‹œ์Šคํ…œ + ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌย ๊ธฐ๋ฐ˜์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

๐ŸŽฎย ์‹ค์ „ ์ ์šฉ! ์ปค๋งจ๋“œ ํŒจํ„ด

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// ์ปค๋งจ๋“œ ์ธํ„ฐํŽ˜์ด์Šค ์—ญํ• : ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ
interface ActionListener {
  actionPerformed(event: Event): void;
}

// ๊ตฌ์ƒ ์ปค๋งจ๋“œ 1
class AngelListener implements ActionListener {
  actionPerformed(event: Event): void {
    console.log("ํ•˜์ง€๋งˆ!");
  }
}

// ๊ตฌ์ƒ ์ปค๋งจ๋“œ 2
class DevilListener implements ActionListener {
  actionPerformed(event: Event): void {
    console.log("ํ•ด!");
  }
}

// ํด๋ผ์ด์–ธํŠธ ์—ญํ• 
function SwingObserverEx() {
  const button = document.getElementById("actionButton");

  if (!button) return;

  const angelListener = new AngelListener();
  const devilListener = new DevilListener();

  // ์ธ๋ณด์ปค ์—ญํ• : ๋ฒ„ํŠผ ์ด๋ฒคํŠธ์— ์ปค๋งจ๋“œ ๋“ฑ๋ก
  button.addEventListener("click", (e) => {
    angelListener.actionPerformed(e);
    devilListener.actionPerformed(e);
  });
}

// ์‹คํ–‰
SwingObserverEx();

Reference

https://velog.io/@toma/ํ—ค๋“œ-ํผ์ŠคํŠธ-๋””์ž์ธ-ํŒจํ„ด-6์žฅ-์ปค๋งจ๋“œ-ํŒจํ„ด-in-Swift

https://velog.io/@ljo_0920/๋””์ž์ธ-ํŒจํ„ด-์ปค๋งจ๋“œ-ํŒจํ„ด

https://faun.pub/head-first-design-patterns-using-go-5-encapsulating-invocation-the-command-pattern-2f8c0a79d1c7

https://greensky0026.tistory.com/278#google_vignette

This post is licensed under CC BY 4.0 by the author.