Contents

Strategy_pattern

strategy pattern ์ด๋ž€?

Strategy Pattern์€ ๊ฐ์ฒด๋‚ด์—์„œ ํ–‰๋™์„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๊ณ , original context class ๋‚ด์—์„œ ์„œ๋กœ ์ƒํ˜ธ๊ตํ™˜ ํ•  ์ˆ˜ ์žˆ๋Š” ํŒจํ„ด์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์บก์Šํ™”ํ•˜์—ฌ ๋ณ€๊ฒฝ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด์ฃผ๋Š” ๋””์ž์ธ ํŒจํ„ด์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์œ„ ๊ตฌ์กฐ์—์„œ ๊ฐ€์žฅ ์ƒ์œ„์— ์žˆ๋Š” class๋ฅผ context class๋ผ ํ•  ๋•Œ, context class์˜ ์—ญํ• ์€ strategy interface๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. strategy interface ๋Š” ๋ชจ๋“  ๊ฒฌ๊ณ ํ•œ strategies์— ๊ณตํ†ต๋˜๋Š” ๋ถ€๋ถ„์ด๊ณ , ๊ฒฌ๊ณ ํ•œ strategy๋Š” ์–ด๋–ค ํ–‰๋™์„ ํ•ด์•ผํ•  ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋””์ž์ธ์„ ๊ตฌ์„ฑํ•œ๋‹ค๋ฉด, context class๋Š” ๊ฐ strategy๊ฐ€ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋“  ์ฐธ์กฐํ•˜๋Š” strategy๊ฐ€ ๊ทธ ํ–‰๋™์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋กœ์ง๋งŒ ๊ตฌ์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์™œ strategy pattern์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€?

์ตœ์ ์˜ ๊ธธ์„ ์•Œ๋ ค์ฃผ๋Š” ๋„ค๋น„๊ฒŒ์ด์…˜ ์•ฑ์ด ์žˆ๋‹ค๊ณ  ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด ์•ฑ์€ ํ˜„์žฌ ์ž๋™์ฐจ๋กœ ๋ชฉ์ ์ง€๊นŒ์ง€ ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์ตœ์ ์˜ ๋ฃจํŠธ๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ๊ทธ ๋ฃจํŠธ๋ฅผ ์•ฑ์— ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

1
2
3
4
5
class Navigator {
  public routeForCar(A,B) {
    ... calulate optimal route when user use car
  }
}

์•ฑ์ด ์ปค์ง์— ๋”ฐ๋ผ, ๋งŽ์€ ์‚ฌ์šฉ์ž๊ฐ€ ๋“ค์–ด์˜ค๊ณ , ์‚ฌ์šฉ์ž๋“ค์€ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์š”๊ตฌํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ฑธ์—ˆ์„ ๋•Œ ์ตœ์ ์˜ ๋ฃจํŠธ๋ฅผ ์•Œ๊ณ  ์‹ถ์€ ์‚ฌ์šฉ์ž, ์‚ฌ์ดํด์„ ํƒ”์„ ๋•Œ ์ตœ์ ์˜ ๋ฃจํŠธ๋ฅผ ์•Œ๊ณ  ์‹ถ์€ ์‚ฌ์šฉ์ž, ๋Œ€์ค‘๊ตํ†ต์„ ์ด์šฉํ–ˆ์„ ๋•Œ ์ตœ์ ์˜ ๋ฃจํŠธ๋ฅผ ์•Œ๊ณ  ์‹ถ์€ ์‚ฌ์šฉ์ž... ๊ทธ๋Ÿด ๋•Œ๋งˆ๋‹ค Navigator ์•ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Navigator {
  public routeForCar(A,B) {
    ... calulate optimal route when user use car
  }
  public routeForWalker(A,B) {
    ... calulate optimal route when user use walking
  }
  public routeForPublicTransport(A,B) {
    ... calulate optimal route when user use transport
  }
  ...
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ์†์„ ํ•˜๊ณ , context class์— ์ •์˜๋œ ๋ฉ”์„œ๋“œ๋ฅผ overriding ํ•˜๊ฒŒ ๋˜๋ฉด, ๊ฐ ๋‹ค๋ฅธ ๋™์ž‘์„ ํ•  ์ˆ˜ ์žˆ๊ธด ํ•˜๊ฒ ์ง€๋งŒ ์ฝ”๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์„ ๋ฟ๋”๋Ÿฌ, ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ๋„ ํž˜๋“ค์–ด์ง‘๋‹ˆ๋‹ค.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Navigator {
  public calculateOptimalRoute(A,B){

  }
}

class Walker extends Navigator{}

class Car extends Navigator {}

class PublicTransport extends Navigator {}

๋”ฐ๋ผ์„œ, Navigator ํด๋ž˜์Šค๋Š” interface๋ฅผ ์ฐธ์กฐํ•˜๊ณ , ํ–‰๋™์ด ๋ฐ”๋€” ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„๋“ค์€ interface๋ฅผ ๊ฐ๊ฐ ๊ตฌํ˜„ํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ณผ์ •์—์„œ ์˜๋„์น˜ ์•Š๊ฒŒ ๋ฐœ์ƒํ•˜๋Š” ์ผ์„ ์ค„์ด๋ฉด์„œ ์‹œ์Šคํ…œ์˜ ์œ ์—ฐ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๋ฐฉ์‹์„ ์ ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„  ๋ฐ”๋€Œ๋Š” ๋ถ€๋ถ„๊ณผ ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ๋ถ€๋ถ„์„ ์ƒ๊ฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์‚ฌ์šฉ์ž๋Š” ์ถœ๋ฐœ์ง€์™€ ๋ชฉ์ ์ง€๋ฅผ ์„ค์ •ํ•œ๋‹ค๋Š” ํ–‰๋™์€ ๋ฐ”๋€Œ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น ๊ธฐ๋Šฅ์€ ๋ชจ๋“  strategy class๊ฐ€ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋”ฐ๋ผ ์ตœ์ ์˜ ๋ฃจํŠธ๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ์‹์—” ์ฐจ์ด๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋Ÿฌํ•œ ํ–‰๋™์€ ๊ฐ strategy class์—์„œ ๊ตฌํ˜„ํ•˜๋ฉด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 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
53
54
55
56
class Navigation {
  private strategy: Strategy;

  constructor(strategy: Strategy) {
    this.strategy = strategy;
  }

  public setStrategy(strategy: Strategy) {
    this.strategy = strategy;
  }

  public doSomethingBussinessLogic(): void {
    // input start point and end point
    this.strategy.setStartAndEndPoint("a", "b");
    const result = this.strategy.doAlgorithm(["a", "b", "c", "d", "e"]);
    console.log(result.join(","));
  }
}

interface Strategy {
  setStartAndEndPoint(start: string, end: string);
  doAlgorithm(data: string[]): string[];
}

class User implements Strategy {
  private startPoint: string;
  private endPoint: string;
  doAlgorithm(data: string[]): string[] {
    return data;
  }
  setStartAndEndPoint(start: string, end: string) {
    this.startPoint = start;
    this.endPoint = end;
  }
}

class Walker extends User {
  doAlgorithm(data: string[]): string[] {
    return data.sort();
  }
}

class Car extends User {
  doAlgorithm(data: string[]): string[] {
    return data.sort();
  }
}

class PublicTransport extends User {
  doAlgorithm(data: string[]): string[] {
    return data.reverse();
  }
}

const navigation = new Navigation(new Walker());
navigation.doSomethingBussinessLogic();

strategy pattern์„ ์ ์šฉ์‹œํ‚ฌ๋งŒํ•œ ๊ณณ

  • ๋Ÿฐํƒ€์ž„ ์‹œ, ๋‹ค์–‘ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ ์šฉ์‹œํ‚ฌ ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ
  • ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ํด๋ž˜์Šค๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ๊ทธ ํด๋ž˜์Šค๋“ค์ด ํŠน์ •ํ–‰๋™์„ ์ œ์™ธํ•˜๊ณ ๋Š” ๋น„์Šทํ•œ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ๊ฒฝ์šฐ

strategy pattern์˜ ์žฅ๋‹จ์ 

  • ์žฅ์ 
    • open/closed principle์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ์ฆ‰, ์ƒˆ๋กœ์šด ์ „๋žต์„ ์ถ”๊ฐ€ํ•  ๋•Œ, context class๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ ๋„ ์ƒˆ๋กœ์šด ์ „๋žต์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • Inheritance๋ฅผ Composition์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋น„์ง€๋‹ˆ์Šค๋กœ์ง์—์„œ ํ•ด๋‹น ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•  ๋•Œ, ๊ตฌํ˜„์ฒด๋ฅผ ๋ถ„๋ฆฌ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋‹จ์ 
    • ์ ์ ˆํ•œ ์ „๋žต์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ „๋žต๋“ค๊ฐ„์˜ ์ฐจ์ด๋ฅผ ์•Œ์•„์•ผ ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
    • lambda๊ฐ™์€ ์ต๋ช…ํ•จ์ˆ˜๋กœ ์ด๋Ÿฌํ•œ ์ „๋žต์„ ๊ตฌํ˜„ํ•˜์—ฌ, ๊ตณ์ด interface, class๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ ์šฉํ•  strategy pattern ์ด ์ ๊ณ , ์ž์ฃผ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ตณ์ด ์ฝ”๋“œ๋ฅผ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค.