문제

나는 보았다 Wikipedia에 대한이 설명, 특히 C ++ 샘플은 3 개의 클래스를 정의하고 인스턴스를 만들고 호출하는 것의 차이점을 인식하지 못합니다. 내가 본 것은 단지 두 개의 다른 클래스를 프로세스에 배치하는 것이었고 어디에 혜택이 있을지 알 수 없습니다. 이제 나는 명백한 것을 놓치고 있다고 확신합니다 (나무를위한 나무) - 누군가가 결정적인 실제 예를 사용하여 설명해 주시겠습니까?


내가 지금까지 답을 얻을 수있는 것은 더 복잡한 방법 인 것 같습니다.

have an abstract class: MoveAlong with a virtual method: DoIt()
have class Car inherit from MoveAlong, 
     implementing DoIt() { ..start-car-and-drive..}
have class HorseCart inherit from MoveAlong, 
     implementing DoIt() { ..hit-horse..}
have class Bicycle inherit from MoveAlong, 
     implementing DoIt() { ..pedal..}
now I can call any function taking MoveAlong as parm 
passing any of the three classes and call DoIt
Isn't this what Strategy intents? (just simpler?)

EDIT-UPDATE] 위에서 언급 한 함수는이 새로운 클래스에서 구현 된 알고리즘을 기반으로 필요에 따라 Movealong이 속성이되는 다른 클래스로 대체됩니다. (허용 된 답변에서 입증 된 것과 유사합니다.)


편집 업데이트 결론

전략 패턴에는 사용이 있지만 키스에 대한 강한 신자이며 더 간단하고 난처한 기술을 덜하는 경향이 있습니다. 대부분 쉽게 관리 할 수있는 코드를 전달하고 싶기 때문에 ( 'Cos'는 아마도 변경해야 할 사람이 될 것입니다!).

도움이 되었습니까?

해결책

요점은 알고리즘을 런타임에 연결할 수있는 클래스로 분리하는 것입니다. 예를 들어, 시계가 포함 된 응용 프로그램이 있다고 가정 해 봅시다. 시계를 그릴 수있는 여러 가지 방법이 있지만 대부분의 경우 기본 기능은 동일합니다. 따라서 클럭 디스플레이 인터페이스를 만들 수 있습니다.

class IClockDisplay
{
    public:
       virtual void Display( int hour, int minute, int second ) = 0;
};

그런 다음 시계 클래스가 타이머에 연결되어 있으며 초당 시계 디스플레이를 업데이트합니다. 그래서 당신은 다음과 같은 것을 가질 것입니다.

class Clock
{
   protected:
      IClockDisplay* mDisplay;
      int mHour;
      int mMinute;
      int mSecond;

   public:
      Clock( IClockDisplay* display )
      {
          mDisplay = display;
      }

      void Start(); // initiate the timer

      void OnTimer()
      {
         mDisplay->Display( mHour, mMinute, mSecond );
      }

      void ChangeDisplay( IClockDisplay* display )
      {
          mDisplay = display;
      }
};

그런 다음 런타임에 적절한 디스플레이 클래스로 시계를 인스턴스화합니다. 즉, ClockDisplayDigital, ClockDisplayAnalog, ClockDisplayMartian 모두 ICLockDisplay 인터페이스를 구현할 수 있습니다.

따라서 나중에 시계 클래스를 엉망으로 만들 필요없이 새 클래스를 만들고 유지 관리 및 디버그를 지저분한 방법을 무시하지 않고도 모든 유형의 새 클럭 디스플레이를 추가 할 수 있습니다.

다른 팁

Java에서는 암호 입력 스트림을 사용하여 다음과 같은 암호를 해독합니다.

String path = ... ;
InputStream = new CipherInputStream(new FileInputStream(path), ???);

그러나 암호 스트림은 어떤 암호화 알고리즘을 사용하려고하는지 또는 블록 크기, 패딩 전략 등에 대한 지식이 없습니다. 새로운 알고리즘은 항상 추가 될 때 하드 코딩하는 것이 실용적이지 않습니다. 대신 우리는 암호를지나갑니다 전략 대상 암호 해독을 수행하는 방법을 알려주려면 ...

String path = ... ;
Cipher strategy = ... ;
InputStream = new CipherInputStream(new FileInputStream(path), strategy);

일반적으로 알고있는 객체가있을 때마다 전략 패턴을 사용합니다. 무엇 해야하지만 그렇지 않습니다 어떻게 그것을하기 위해. 또 다른 좋은 예는 스윙의 레이아웃 관리자입니다.이 경우에는 잘 작동하지 않았습니다. 완전히 그리드백 재미있는 일러스트레이션을 위해.

NB : 스트림에서 스트림을 포장하는 것이 예입니다. 데코레이터.

전략과 결정/선택에는 차이가 있습니다. 대부분의 시간 A는 코드에서 결정/선택을 처리하고 if ()/switch () 구성을 사용하여 인식합니다. 전략 패턴은 사용법에서 논리/알고리즘을 분리 할 필요가있을 때 유용합니다.

예를 들어, 다른 사용자가 리소스/업데이트를 확인하는 폴링 메커니즘을 생각해보십시오. 이제 더 빠른 처리 시간 또는 자세한 내용으로 일부 권한이있는 사용자에게 통보되기를 원할 수 있습니다. Essentailly 사용되는 논리는 사용자 역할에 따라 변경됩니다. 전략은 디자인/아키텍처 뷰 포인트에서 의미가 있습니다. 더 낮은 수준의 세분성에서는 항상 의문을 제기해야합니다.

전략 패턴을 사용하면 메인 클래스를 연장하지 않고 다름 방학을 악용 할 수 있습니다. 본질적으로, 당신은 전략 인터페이스 및 구현 및 메인 클래스 대의원에 모든 가변 부품을 넣고 있습니다. 기본 객체가 하나의 전략 만 사용하는 경우 각 서브 클래스에서 초록 (순수한 가상) 메소드와 다른 구현이있는 것과 거의 동일합니다.

전략 접근 방식은 몇 가지 이점을 제공합니다.

  • 런타임시 전략을 변경할 수 있습니다.이를 런타임시 클래스 유형 변경과 비교할 수 있습니다.
  • 하나의 메인 클래스는 여러 가지 방식으로 재결합 할 수있는 하나 이상의 전략을 사용할 수 있습니다. 트리를 걷고 각 노드와 현재 결과를 기반으로 함수를 평가하는 클래스를 고려하십시오. 도보 전략 (깊이 우선 또는 폭이 먼저)과 계산 전략 (일부 functor-'count positial numbages'또는 'sum')을 가질 수 있습니다. 전략을 사용하지 않으면 걷기/계산의 각 조합에 대해 서브 클래스를 구현해야합니다.
  • 코드는 전략을 수정하거나 이해하는 것이 더 쉽습니다. 전략 전체를 이해할 필요는 없습니다.

단점은 많은 경우 전략 패턴이 과잉이라는 것입니다. 스위치/케이스 연산자가 이유가 있습니다. 간단한 제어 흐름 문 (스위치/케이스 또는 IF)부터 시작하여 필요한 경우 클래스 계층으로 이동하고 변동성이 하나 이상인 경우 전략을 추출하십시오. 기능 포인터는이 연속체의 한가운데 어딘가에 떨어집니다.

권장 독서 :

이를 보는 한 가지 방법은 실행하려는 다양한 조치가 있고 해당 조치가 런타임에 결정된 경우입니다. 해시 가능 또는 전략 사전을 만들면 명령 값 또는 매개 변수에 해당하는 전략을 검색 할 수 있습니다. 하위 집합이 선택되면 전략 목록을 반복하고 연속적으로 실행할 수 있습니다.

하나의 구체적인 예는 순서 총계를 계산하는 것입니다. 귀하의 매개 변수 또는 명령은 기본 가격, 지방 세금, 도시 세, 주 세금, 지상 운송 및 쿠폰 할인입니다. 주문 변동을 처리 할 때 유연성이 작용합니다. 일부 주에는 판매 세가 없으며 다른 주문에는 쿠폰을 적용해야합니다. 계산 순서를 동적으로 할당 할 수 있습니다. 모든 계산을 설명하는 한 재 컴파일없이 모든 조합을 수용 할 수 있습니다.

이 디자인 패턴이 허용됩니다 알고리즘 캡슐화 수업에서.

전략 인 클라이언트 클래스를 사용하는 클래스는 알고리즘 구현에서 분리됩니다. 알고리즘 구현을 변경하거나 클라이언트를 수정하지 않고도 새 알고리즘을 추가 할 수 있습니다. 클라이언트는 동적으로 수행 할 수 있습니다. 클라이언트는 그가 사용할 알고리즘을 선택할 수 있습니다.

예를 들어, 이미지를 파일에 저장 해야하는 응용 프로그램을 상상해보십시오. 이미지는 다른 형식으로 저장할 수 있습니다 (PNG, JPG ...). 인코딩 알고리즘은 모두 동일한 인터페이스를 공유하는 다른 클래스에서 구현됩니다. 클라이언트 클래스는 사용자 선호도에 따라 하나를 선택합니다.

Wikipedia 예제에서 이러한 인스턴스는 해당 인스턴스가 속한 클래스를 신경 쓰지 않아도되는 함수로 전달 될 수 있습니다. 함수는 단지 호출됩니다 execute 물체가 지나가고 옳은 일이 일어날 것임을 알고 있습니다.

전략 패턴의 일반적인 예는 파일이 UNIX에서 작동하는 방법입니다. 파일 디스크립터가 주어지면, 당신은 그것을 읽고, 그것을 쓰고, 그것을 폴링하고, 그것을 찾고, 보내실 수 있습니다. ioctls to it etcl 그리고이 경우 글은이 경우에도 잘 작동합니다.)

즉, 파일 대 디렉토리 등을 처리하기 위해 별도의 코드를 작성하지 않고도 이러한 다양한 유형의 "파일"을 처리하기 위해 일반 코드를 작성할 수 있습니다. UNIX 커널은 통화를 올바른 코드로 위임하는 것을 관리합니다.

이제 이것은 커널 코드에 사용 된 전략 패턴이지만 실제 세계 예제 인 사용자 코드 여야한다는 것을 지정하지는 않았습니다. :-)

전략 패턴은 간단한 아이디어에 대해 작동합니다. 즉, 전략/알고리즘을 실행 시간에 변경할 수 있도록 "상속에 대한 구성"을 선호합니다. 설명하기 위해 메일 메가 지, 채팅 메이지 등 유형에 따라 다른 메시지를 암호화 해야하는 예를 들어 보자.

class CEncryptor
{
    virtual void encrypt () = 0;
    virtual void decrypt () = 0;
};
class CMessage
{
private:
    shared_ptr<CEncryptor> m_pcEncryptor;
public:
    virtual void send() = 0;

    virtual void receive() = 0;

    void setEncryptor(cost shared_ptr<Encryptor>& arg_pcEncryptor)
    {
        m_pcEncryptor =  arg_pcEncryptor;
    }

    void performEncryption()
    {
        m_pcEncryptor->encrypt();
    }
};

이제 런타임에 CMESSAGE에서 상속 된 다른 메시지 (CmailMessage : Public CMESSAGE)가 다른 암호화기 (CDESENCRYPTOR : PUBLIC CENCRYPTOR)와 함께 인스턴스화 할 수 있습니다.

CMessage *ptr = new CMailMessage();
ptr->setEncryptor(new CDESEncrypto());
ptr->performEncryption();
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top