전략 패턴 및 명령 패턴 사용


121

두 디자인 패턴 모두 알고리즘을 캡슐화하고 호출 클래스에서 구현 세부 사항을 분리합니다. 내가 알아볼 수있는 유일한 차이점은 전략 패턴은 실행을위한 매개 변수를 사용하지만 명령 패턴은 그렇지 않다는 것입니다.

명령 패턴은 생성 될 때 사용할 수있는 모든 정보를 필요로하며 호출을 지연시킬 수 있습니다 (아마도 스크립트의 일부로).

한 패턴을 사용할 것인지 다른 패턴을 사용할 것인지 결정하는 기준은 무엇입니까?

답변:


94

이 두 패턴의 차이점을 설명하는 데 도움이되는 여러 GoF 디자인 패턴의 캡슐화 계층 테이블을 포함합니다. 바라건대 각각이 캡슐화하는 것을 더 잘 설명하므로 내 설명이 더 의미가 있습니다.

먼저, 계층 구조는 테이블의 어느 쪽에서 시작하는지에 따라 주어진 패턴을 적용 할 수있는 범위 또는 특정 수준의 세부 정보를 캡슐화하는 데 사용할 적절한 패턴을 나열합니다.

디자인 패턴 캡슐화 계층 테이블

표에서 볼 수 있듯이 Strategy Pattern 개체는 알고리즘 구현의 세부 정보를 숨기므로 다른 전략 개체를 사용하면 동일한 기능을 수행하지만 다른 방식으로 수행됩니다. 각 전략 개체는 특정 요소에 대해 최적화되거나 다른 매개 변수에서 작동 할 수 있습니다. 공통 인터페이스를 사용하여 컨텍스트는 둘 중 하나와 안전하게 작업 할 수 있습니다.

명령 패턴은 알고리즘보다 훨씬 더 작은 수준의 세부 정보를 캡슐화합니다. 객체에 메시지를 보내는 데 필요한 세부 정보 (수신자, 선택자 및 인수)를 인코딩합니다. 프로세스 실행의 이러한 작은 부분을 객관화 할 때의 이점은 이러한 메시지를 세부 사항을 하드 코딩하지 않고도 일반적인 방식으로 다른 시점 또는 위치를 따라 호출 할 수 있다는 것입니다. 이를 통해 메시지를 한 번 이상 호출하거나 실행 전에 특정 호출의 세부 정보를 알 필요없이 시스템의 다른 부분이나 여러 시스템으로 전달할 수 있습니다.

디자인 패턴의 일반적인 경우와 같이 패턴 이름을 포함하기 위해 모든 구현이 세부적으로 동일 할 필요는 없습니다. 세부 사항은 구현 및 개체에서 인코딩되는 데이터와 메서드 인수로 인코딩되는 데이터에 따라 다를 수 있습니다.


따라서 "필터 파이프 라인"으로 결과를 필터링하고 델리게이트를 필터로 사용하는 시스템이 있다면 (각 필터의 ​​알고리즘이 함수 내에 캡슐화되는) 명령 패턴으로 간주 될까요? 이 경우 필터 기능에 대한 위임은 각 필터가 입력 및 출력 측면에서 준수해야하는 종류의 계약을 제공하는 것으로 간주합니다.
KTF

4
@KTF, 아니. 명령 패턴은 객체의 메서드를 호출하는 데 필요한 정보 (예 : 수신기, 선택기, 인수)가 대부분 (전부는 아니지만)있는 객체를 사용합니다. 책임의 사슬, 수집 및 설명하는 파이프 라인 패턴과 같은 다른 디자인 패턴에서 사용할 수있는 단순한 패턴입니다. 대리인이 제공하는 "정렬 계약"은 인터페이스라는 또 다른 패턴입니다.
Huperniketes

50

전략은 알고리즘을 캡슐화합니다. 명령은 발신자와 요청 수신자를 분리하여 요청을 객체로 변환합니다.

그것이 알고리즘이라면 어떤 일이 어떻게 될지 전략을 사용하십시오. 실행에서 메서드 호출을 분리해야하는 경우 Command를 사용합니다. 명령은 작업이나 트랜잭션과 같이 나중에 사용하기 위해 메시지를 대기열에 넣을 때 자주 사용됩니다.


만든 감지 것을 en.wikipedia.org/wiki/Command_Pattern의 클라이언트와 호출자가 연결되어 있지만, 동시에 그들은 서로에 대해 잘 모릅니다!
Kalpesh Soni

26

아주 오래된 질문에 대답합니다. (가장 많이 득표 한 대신 최신 답변을 보는 사람이 있습니까?)

유사성 때문에 갖는 것은 타당한 혼란입니다. 전략 및 명령 패턴 모두 캡슐화를 사용 합니다 . 하지만 그렇다고해서 똑같지는 않습니다.

주요 차이점 은 캡슐화 된 내용 을 이해 하는 것 입니다. 두 패턴이 모두 의존하는 OO 원칙은 다양한 것을 캡슐화하는 것 입니다.

전략의 경우에는 알고리즘이 다릅니다 . 예를 들어 하나의 전략 객체는 XML 파일로 출력하는 방법을 알고 있고 다른 하나는 JSON으로 출력하는 방법을 알고 있습니다. 다른 알고리즘은 다른 클래스에서 유지 ( 캡슐화 )됩니다. 그렇게 간단합니다.

명령의 경우 요청 자체 가 다릅니다 . 요청은 File Menu > Delete또는 Right Click > Context Menu > Delete또는 에서 올 수 있습니다 Just Delete Button pressed. 세 가지 경우 모두 동일한 유형의 명령 개체 3 개를 생성 할 수 있습니다. 이러한 명령 개체는 3 개의 삭제 요청 만 나타냅니다. 삭제 알고리즘이 아닙니다. 이제 요청은 객체의 무리이므로 쉽게 관리 할 수 ​​있습니다. 갑자기 실행 취소 또는 다시 실행과 같은 기능을 제공하는 것이 사소 해집니다.

명령이 요청 된 논리를 구현하는 방법은 중요하지 않습니다. execute ()를 호출하면 삭제를 트리거하는 알고리즘을 구현하거나 다른 객체에 위임 할 수도 있고 전략에 위임 할 수도 있습니다. 명령 패턴의 구현 세부 사항 일뿐입니다. 이것은 같이 이름이 왜 명령 이에게 정중 방법은 아니지만 요청 : -)

전략과 대조하십시오. 이 패턴은 실행되는 실제 논리 에만 관련됩니다 . 그렇게하면 최소한의 클래스 집합으로 다양한 동작 조합을 달성하여 클래스 폭발을 방지하는 데 도움이됩니다.

Command는 캡슐화에 대한 이해를 넓히는 데 도움이되며 Strategy는 캡슐화와 다형성의 자연스러운 사용을 제공합니다.


15

제가 보는 방식은 동일한 작업을 수행하는 여러 가지 방법이 있다는 것입니다. 각각은 전략이며 런타임에 어떤 전략이 실행되는지 결정합니다.

먼저 StrategyOne을 시도해보고 결과가 충분하지 않으면 StrategyTwo를 시도해보세요 ...

명령은 TryToWalkAcrossTheRoomCommand와 같이 발생해야하는 별개의 작업에 바인딩됩니다. 이 명령은 어떤 개체가 방을 가로 질러 걸어 가려고 할 때마다 실행되지만, 그 안에서 방을 가로 질러 걸어 가기 위해 StrategyOne 및 StrategyTwo를 시도 할 수 있습니다.


2
RE : "동일한 일을하는 여러 방법"-전략의 일반적인 예와 상충되는 것 같습니다. 특히 더하기, 빼기, 곱하기 등을 수행하는 구현 클래스가있는 것들입니다. 아마도 그것들은 좋은 예가 아닐까요?
Joshua Davis

1
@JoshuaDavis이 모든 "substratagies"는 하나의 전략 인 산술 연산 의 특별한 경우입니다 . 공통 인수 (피연산자 2 개)가 있으며 결과로 하나의 값을 생성합니다. 구현에 따라 거의 동일한 작업을 수행합니다 (블랙 박스가 됨). 좋은 예 =) : 그래서, 정반대 여기 충돌을 볼 수 없지만,
jungle_mole

7

제 생각에는 틀릴 수도 있지만 명령 을 실행 기능 또는 반응으로 취급합니다 . 최소한 두 명의 플레이어가 있어야합니다 : 액션을 요청하는 플레이어와 액션을 실행하는 플레이어. GUI는 명령 패턴의 일반적인 예입니다.

  • 응용 프로그램 도구 모음의 모든 단추는 일부 작업과 연결됩니다.
  • 이 경우 버튼이 실행자입니다.
  • 이 경우 작업은 명령입니다.

명령은 일반적으로 일부 범위 또는 비즈니스 영역에 제한되지만 필수는 아닙니다 execute(). 하나의 응용 프로그램 내 에서 청구서를 발행하거나 로켓을 시작하거나 동일한 인터페이스 (예 : 단일 메서드)를 구현하는 파일을 제거하는 명령이있을 수 있습니다 . 종종 명령은 자체 포함되어 있으므로 의도 한 작업을 처리하기 위해 실행자로부터 아무것도 필요하지 않습니다 (필요한 모든 정보는 생성시 제공됨). 때로는 명령이 상황에 따라 달라지며이 상황을 발견 할 수 있어야합니다. ( 백 스페이스 명령은 이전 문자를 올바르게 제거하기 위해 텍스트에서 캐럿 위치를 알아야합니다. 롤백 명령은 롤백 할 현재 트랜잭션을 검색해야합니다. ...).

그만큼 전략은 조금 다르다 : 그것은 더 일부 지역에 바인딩됩니다. 전략은 날짜를 형식화하는 규칙 (UTC? 로케일 특정?) ( "날짜 형식 기"전략) 또는 기하학적 그림에 대한 제곱을 계산하는 규칙 ( "제곱 계산기"전략)을 정의 할 수 있습니다. 전략은 이러한 의미에서 무언가를 입력 ( "날짜", "그림", ...)으로 받아들이고 그에 따라 결정을 내리는 플라이 웨이트 객체입니다. 아마도 전략이 아닌 최고,하지만 좋은 예와 연결된 하나 javax.xml.transform.Source의 인터페이스 : 전달 된 객체인지에 따라 DOMSource또는 SAXSource또는 StreamSource전략 (= XSLT 변환기이 경우)를 처리하는 다른 규칙을 적용합니다. 구현은 단순 switch하거나 책임 사슬 패턴을 포함 할 수 있습니다 .

그러나 실제로이 두 패턴 사이에는 공통점이 있습니다. 명령과 전략은 동일한 의미 영역 내에서 알고리즘을 캡슐화합니다.


1
명령을 콜백 함수 또는 반응으로 취급합니다. 최소한 두 명의 플레이어가 있어야합니다. 한 명은 행동을 요청하고 한 명은 실행하는 ...- 당신이 말하려는 내용은 이해하지만 '콜백'이라는 단어는 자주 사용하지 않습니다. '콜백'은 비동기 호출을 의미하며 명령 패턴이 유용하기 위해 비동기 호출을 수행 할 필요가 없습니다. 적절한 사례 : Microsoft Word. 도구 모음 버튼을 클릭하고 바로 가기 키 프레스는 비동기 명령 호출하지 않지만, 우리는이 경우에 유용 할 것이다 방법 명령 패턴을 감상 할 수있다
짐 G.

Jim이 말했듯이 콜백에 대한 참조를 제거하기 위해 편집 할 것이지만 동의합니다.
JARC

감사합니다. 몇 가지 확장을했습니다. 동의 / 동의하지 않는 경우 알려주세요.
dma_k

5

명령:

기본 구성 요소 :

  1. Command 는 다음과 같은 추상 명령에 대한 인터페이스를 선언합니다.execute()
  2. 수신자 는 특정 명령을 실행하는 방법을 알고 있습니다.
  3. Invoker 는실행 해야하는 ConcreteCommand 를 보유합니다.
  4. 클라이언트 ConcreteCommand를 생성하고 수신자를 할당합니다.
  5. ConcreteCommand Command Receiver 간의 바인딩을 정의합니다.

워크 플로우 :

클라이언트 호출 Invoker => Invoker 호출 ConcreteCommand => ConcreteCommand 는 추상 Command 를 구현하는 Receiver 메서드를 호출합니다. 메서드 .

장점 : 클라이언트는 Command 및 Receiver의 변경 사항에 영향을받지 않습니다. 호출자는 클라이언트와 수신자 간의 느슨한 결합을 제공합니다. 동일한 Invoker로 여러 명령을 실행할 수 있습니다.

명령 패턴을 사용하면동일한 Invoker 를 사용하여다른 수신기 에서 명령을 실행할 수 있습니다. 호출자가 다음 유형을 인식하지 못합니다. 수신자

개념의 이해,이 JournalDev에 한 번 봐이 기사 에 의해 판 카지 쿠마 와 dzone의 기사 에 의해 제임스 Sugrue 위키 백과 링크에 추가합니다.

명령 패턴을 사용 하여

  1. 호출자 및 명령 수신자 분리

  2. 콜백 메커니즘 구현

  3. 실행 취소 및 다시 실행 기능 구현

  4. 명령 기록 유지

java.lang.ThreadCommand 패턴 의 좋은 구현입니다 . Thread 를 호출자 및 Runnable 을 구현하는 클래스 로 ConcreteCommonad / Receiver로 , run()메소드를 Command 로 처리 할 수 ​​있습니다 .

명령 패턴의 실행 취소 / 다시 실행 버전은 Theodore Norvell의 기사 에서 읽을 수 있습니다.

전략:

전략 패턴은 이해하기 매우 간단합니다. 이 패턴을 사용하는 경우

알고리즘에 대한 여러 구현이 있으며 알고리즘 구현은 특정 조건에 따라 런타임에 변경 될 수 있습니다 .

항공사 예약 시스템의 요금 구성 요소의 예를 들어보십시오.

항공사는 성수기 및 성수기 이외의 시간대에 다른 요금을 제공하고자합니다. 여행 성수기가없는 날에는 매력적인 할인을 제공하여 수요를 자극하고자합니다.

전략 패턴 의 핵심 사항 :

  1. 행동 패턴입니다
  2. 위임을 기반으로 함
  3. 메서드 동작을 수정하여 객체의 내장을 변경합니다.
  4. 알고리즘 계열간에 전환하는 데 사용됩니다.
  5. 런타임에 개체의 동작을 변경합니다.

코드 예제가있는 관련 게시물 :

명령 디자인 패턴 사용

전략 패턴의 실제 사례


0

저에게 차이는 의도 중 하나입니다. 두 패턴의 구현은 매우 유사하지만 용도는 다릅니다.

  • 전략 '의 경우, 객체를 사용하여 구성 요소가 알고있는 어떤 물체가하는 (그리고 자신의 작품의 일부를 수행하는 데 사용),하지만 상관하지 않는다 어떻게 그것을 않습니다.

  • 명령의 경우, 객체를 사용하여 구성 요소는 어느 쪽도 모른다 어떤 명령은하지 않고 어떻게 그것을 않습니다 - 그것은 단지 그것을 호출하는 방법을 알고있다. 호출자의 작업은 명령을 실행하는 것입니다. 명령에 의해 수행되는 처리는 호출자의 핵심 작업의 일부를 구성하지 않습니다.

이것이 차이점입니다. 구성 요소를 사용하는 개체가 실제로 구성 요소의 기능을 알고 있거나 관심을 갖고 있습니까? 대부분의 경우 이는 패턴 객체가 호출자에게 값을 반환하는지 여부에 따라 결정될 수 있습니다. 호출자가 패턴 객체가하는 일에 관심이 있다면 아마도 무언가를 반환하기를 원할 것이고 전략이 될 것입니다. 반환 값에 대해 신경 쓰지 않는다면 아마도 Command 일 것입니다 (참고로 Java Callable과 같은 것은 여전히 ​​Command입니다. 값을 반환하더라도 호출자는 값에 대해 신경 쓰지 않습니다. 원래 명령을 제공 한 것).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.