๐Ÿ“— ๊ฐ์ฒด ํ–‰๋™: ์ „๋žต

13706 ๋‹จ์–ด designpatterns

TL;DR;



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

์ •์˜



์ „๋žต ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ณต์‹ ๋‹ค์ด์–ด๊ทธ๋žจ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.


IStrategy ๊ฐœ์ฒด์— ๋Œ€ํ•œ ์ฐธ์กฐ๋ฅผ ๋ณด์œ ํ•˜๋Š” Context ์œ ํ˜•์˜ ๊ฐœ์ฒด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปจํ…์ŠคํŠธ๋Š” ์ผ๋ถ€ ์ž‘์—…์„ ์ด IStrategy ๊ฐœ์ฒด์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

State Pattern ๊ณผ ๊ฑฐ์˜ ๋™์ผํ•˜๊ฒŒ ๋“ค๋ฆฌ์ง€๋งŒ ์ „๋žต์€ ์ปจํ…์ŠคํŠธ ์ธ์Šคํ„ด์Šคํ™” ์‹œ๊ฐ„(์ปจํ…์ŠคํŠธ๊ฐ€ ์ธ์Šคํ„ด์Šคํ™”๋œ ํ›„ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๋™์•ˆ)์— ํ•œ ๋ฒˆ ์„ค์ •๋ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„



์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ด…์‹œ๋‹ค.
์—ฌ์ „ํžˆ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ์žˆ์ง€๋งŒ ์ด๋ฒˆ์—๋Š” ์ฝ”๋ฑ์— ๋” ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋๋‚  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

export default class Player {
  private paramA: number;
  private paramB: number;
  private paramC: number;

  constructor(private codecType: AlgorithmType, private stream: Stream) {
    // Setting up params
  }

  play() {
    const algorithm = this.getAlgorithm();

    switch (algorithm) {
      case 'A':
        this.decodeA();
        break;
      case 'B':
        this.decodeB();
        break;
      case 'C':
        this.decodeC();
        break;
    }

    console.log('>>>> Play');
  }

  private getAlgorithm(): AlgorithmType {
    // Some logic happens here to determine appropriate algorithm.
    return this.codecType;
  }

  private decodeA(): Stream {
    // Actual algorithm to decode the stream in some way
    console.log('>>>> Decoding with A', this.paramA);
    return this.stream;
  }

  private decodeB(): Stream {
    // Actual algorithm to decode the stream in some way
    console.log('>>>> Decoding with B', this.paramB);
    return this.stream;
  }

  private decodeC(): Stream {
    // Actual algorithm to decode the stream in some way
    console.log('>>>> Decoding with C', this.paramC);
    return this.stream;
  }
}


ํ”Œ๋ ˆ์ด์–ด ํด๋ž˜์Šค ๋‚ด์—์„œ ์ŠคํŠธ๋ฆผ์„ ๋””์ฝ”๋”ฉํ•˜๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์–ด๋–ค ํŠน์ • ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€ ๊ฒฐ์ •ํ•˜๋Š” switch ๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ ๋‹น์žฅ์€ ๊ทธ๋ ‡๊ฒŒ ๋‚˜์˜์ง€๋Š” ์•Š์ง€๋งŒ ๋””์ฝ”๋”ฉ ๊ธฐ๋Šฅ์ด ์ˆ˜์‹ญ ์ค„์˜ ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ์‹ค์ œ ์ƒํ™ฉ์„ ์ƒ์ƒํ•ด ๋ณด์‹ญ์‹œ์˜ค.

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

  • ๊ธ€์Ž„, ์ด ๋ชจ๋“  ๊ฒƒ์„ ํ•œ ๊ฐ€์ง€ ์ž‘์€ ๋ณ€ํ™”๋กœ ํ•ด๋ด…์‹œ๋‹ค. ๊ฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•œ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์ง€ ๋ง์ž. ์ด๊ฑฐ ๋ด์š”:

    interface Strategy {
      decode(stream: Stream, context: DecodeContext): Stream;
    }
    
    class StrategyA implements Strategy {
      decode(stream: Stream, context: DecodeContext) {
        // implementation
      }
    }
    


    ์šฐ๋ฆฌ๋Š” TypeScript(JavaScript) ์„ธ๊ณ„์— ์žˆ๊ณ , ํ•จ์ˆ˜๋Š” ์ผ๊ธ‰ ์‹œ๋ฏผ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ•จ์ˆ˜๋ฅผ ์–ด๋””์—๋‚˜ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ณ , ๋‹จ์ง€ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜๋ฅผ ํฌํ•จํ•˜๊ธฐ ์œ„ํ•ด ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

    ๋”ฐ๋ผ์„œ ํŒจํ„ด ๊ตฌํ˜„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    export default class Player {
      private paramA: number;
      private paramB: number;
      private paramC: number;
    
      constructor(private decode: Decode, private stream: Stream) {
        // Setting up params
      }
    
      play() {
        this.decode(this.stream, {
          a: this.paramA,
          b: this.paramB,
          c: this.paramC,
        });
        console.log('>>>> Play');
      }
    }
    


    ๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“  ๋””์ฝ”๋”ฉ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ์ด์ œ ์ž์ฒด ๊ธฐ๋Šฅ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

    export const decodeA: Decode = (stream: Stream, { a }: DecodeContext) => {
      // Actual algorithm to decode the stream in some way
      console.log('>>>> Decoding with A', a);
      return stream;
    };
    
    export const decodeB: Decode = (stream: Stream, { b }: DecodeContext) => {
      // Actual algorithm to decode the stream in some way
      console.log('>>>> Decoding with B', b);
      return stream;
    };
    
    export const decodeC: Decode = (stream: Stream, { c }: DecodeContext) => {
      // Actual algorithm to decode the stream in some way
      console.log('>>>> Decoding with C', c);
      return stream;
    };
    


    ๋น„์šฉ์€ ์–ผ๋งˆ์ž…๋‹ˆ๊นŒ?



    ์ž ์žฌ์  ๋‹จ์ :
  • ํŒŒ์ผ ์ˆ˜๋ฅผ ๋Š˜๋ฆด ์ˆ˜ ์žˆ๋Š”๋ฐ ์ผ๋ถ€์—์„œ๋Š” ์ด๋ฅผ ์ข‹์ง€ ์•Š๊ฒŒ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
  • .
  • ๋ชจ๋“  ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•ด Decode ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•  ๋•Œ ๊ฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ํ•„์š”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ์ด์ƒ์ ์ด์ง€ ๋ชปํ•จ

  • ์ž ์žฌ์  ์žฅ์ :
  • switch ๋ฌธ์„ ์ œ๊ฑฐํ–ˆ์Šต๋‹ˆ๋‹ค
  • .
  • ํ”Œ๋ ˆ์ด์–ด ํด๋ž˜์Šค ์™ธ๋ถ€์—์„œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„์„ ์ด๋™ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค
  • .

    ๊ฒฐ๋ก 



    ๋‚˜๋Š” ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ  ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ ์กฐ๊ฑด๋ฌธ์„ ํ”ผํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜๋ฏ€๋กœ ์ด ํŒจํ„ด์€ ์ง€๊ธˆ๊นŒ์ง€ ๋‚˜์—๊ฒŒ ์ •๋ง ์œ ์šฉํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

    ์กฐ๊ธˆ์ด๋‚˜๋งˆ ๋„์›€์ด ๋˜์—ˆ๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค ๐Ÿ™ƒ
    Source code if needed

    ์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ