디자인 패턴: 전략 패턴

이전 블로그 게시물Intro to Design Patterns에서 행동 패턴의 예로 전략 패턴을 사용했습니다. 이번 포스트에서는 전략 패턴에 대해 좀 더 자세히 설명하고 그에 대한 예를 들어 보겠습니다.

다양한 경로를 통해 식료품점에 갈 수 있는 방법을 알고 있습니까? 또는 휴대폰과 랩톱이 서로 다른 장치임에도 불구하고 어떻게 음악을 재생할 수 있습니까? 여기에서 전략 패턴이 빛을 발합니다.

전략 패턴은 유사하지만 서로 다른 개체가 있을 때 각 개체가 동일한 작업을 수행하는 다른 방법을 가지고 있거나 무언가가 두 가지 이상의 방법으로 달성될 수 있고 이 모든 것을 수용해야 할 때 매우 유용한 행동 디자인 패턴입니다. 방법. 예를 들어 설명하겠습니다.

문제



정사각형의 면적을 계산하는 응용 프로그램이 있다고 가정해 보겠습니다. 다음과 같은 사각형에 대한 클래스를 가질 수 있습니다.

class Square {
  side double;

  function area () {
    return this.side * this.side;
  }
}


주요 기능은 다음과 같습니다.

function main() {
  squareInstance = new Square();
  squareInstance.side = 5;
  print(squareInstance.area);
}


이제 삼각형도 처리해야 하는 새로운 요구 사항이 발생합니다. 그렇게 하는 한 가지 방법은 클래스에 "유형"필드를 추가하고 다음과 같은 유형에 따라 면적을 계산하는 것입니다.

class Shape {
  type string;
  side double;
  base double;
  height double;

  function area () {
    switch this.type {
      case "triangle": return 0.5 * this.base * this.height;
      case "square" : return this.side * this.side;
    }
  }
}


이것은 작동하지만 클래스에 원을 추가하면 어떻게 될까요? 아마 눈치채셨겠지만, 이것은 혼란스러운 솔루션이며 우리가 더 많은 유형을 추가함에 따라 더 혼란스러워질 것입니다. 이 솔루션은 다음과 같은 많은 문제를 야기합니다.
  • 하나의 모양에만 해당되고 다른 모양과 관련이 없는 변수를 추가해야 했습니다. 삼각형에는 밑변과 높이가 있고 정사각형에는 한 변이 있습니다.
  • 클래스의 인스턴스를 초기화하면 오류가 발생하기 쉽습니다. 클라이언트는 단순히 "삼각형"유형의 모양을 만들고 높이 대신 밑변과 측면을 지정할 수 있습니다.
  • 객체 동작을 처리하려면 switch 문 또는 if 문이 필요합니다. 새 유형을 추가할 때마다 개체를 처리하는 모든 함수에 새로운 if/case 문을 추가하게 되므로 프로젝트가 커질수록 문제가 발생합니다. 기본적으로 조건문입니다.

  • 해결책



    전략 패턴은 컨텍스트를 알 필요 없이 유사한 객체가 다른 동작을 가질 수 있도록 하는 것을 목표로 합니다. 또한 코드를 깨끗하고 체계적으로 유지하고 새로운 동작을 원활하게 추가할 수 있습니다. 작동 방식은 다음과 같습니다.
  • 동작이 다른 함수를 인터페이스로 이동합니다.
  • 다른 "유형"을 다른 클래스로 분할합니다.
  • 각각의 새 클래스는 인터페이스를 구현해야 합니다.

  • 코드는 다음과 같습니다.

    interface AreaStrategy {
      function area(){};
    }
    
    class Square implements AreaStrategy {
      side double;
      function area() {
        return this.side * this.side;
      }
    }
    
    class Triangle implements AreaStrategy {
      base double;
      height double;
      function area() {
        return 0.5 * this.base * this.height;
      }
    }
    


    이제 컨텍스트 없이 면적을 계산할 수 있습니다. 모양이 무엇인지 알 필요 없이 모양을 취하고 면적을 직접 계산하는 함수를 가질 수 있습니다. 모든 클래스가 AreaStrategy를 구현하므로 모양은 단순히 AreaStrategy 유형일 수 있습니다. 기능은 다음과 같습니다.

     function calculateArea(shape AreaStrategy){
      return shape.area()
    }
    
    function main() {
      squareInstance = new Square();
      squareInstance.side = 5;
      print(calculateArea(squareInstance))
      // prints "25" i.e. 5 * 5
    
      triangleInstance = new Triangle();
      triangleInstance.base = 10;
      triangleInstance.height = 20;
      print(calculateArea(triangleInstance))
      // prints "100" i.e. 0.5 * 10 * 20
    }
    


    추상화를 사용하여 함수는 개체의 유형을 알 필요 없이 개체만 제대로 작동하면 됩니다. 유형이 있다는 것을 알 필요도 없습니다. 객체가 인터페이스를 구현하는 한 함수에 아무것도 추가하지 않고 작동합니다.

    이제 새 모양이 있으면 새 클래스를 만들고 AreaStrategy 인터페이스를 구현하기만 하면 코드의 다른 부분을 수정할 필요 없이 작동합니다.

    결론



    추상화를 사용하여 전략 패턴을 사용하면 동일한 작업에 대해 다른 동작/알고리즘을 갖는 것이 훨씬 더 쉽고 명확해집니다. 인터페이스를 구현하기만 하면 됩니다. 컨텍스트가 필요하지 않습니다. 단순히 수행 방법보다는 작업에 집중할 수 있습니다.

    Alvaro ReyesUnsplash의 사진

    좋은 웹페이지 즐겨찾기