관찰자 패턴; * 무엇이 바뀌 었는지 아십니까?


10

클래식 Observer 패턴 인터페이스를 정의하는 두 개의 추상 클래스 Subject와 Observer를 만들었습니다. Observer 패턴을 구현하기 위해 그것들에서 파생됩니다. 관찰자는 다음과 같이 보일 수 있습니다.

void MyClass::Update(Subject *subject)
{
    if(subject == myService_)
    {
        DoSomething();
    }
    else if(subject == myOtherService_)
    {
        DoSomethingElse();
    }
}

이것은 괜찮으며 누가 무언가 바꿨 는지 알려줍니다 . 그러나 무엇이 바뀌 었는지 알려주지 않습니다 . 주제에 최신 데이터를 쿼리하기 때문에 때로는 괜찮습니다.하지만 다른 경우 주제에 정확히 무엇이 바뀌 었는지 알아야합니다. Java에서 변경 사항에 대한 세부 정보를 지정하기 위해 notifyObservers () 메소드와 notifyObservers (Object arg) 메소드를 모두 가지고 있습니다 .

제 경우에는 두 가지 다른 동작 중 하나가 주제에 대해 발생했는지, 특정 조치 인 경우 해당 동작과 관련된 정수를 알아야합니다.

그래서 내 질문은 :

  1. Java와 마찬가지로 일반적인 인수를 전달하는 C ++ 방법은 무엇입니까?
  2. 관찰자가 가장 좋은 패턴입니까? 아마도 어떤 종류의 이벤트 시스템일까요?

최신 정보

Observer 패턴을 템플릿 화하는 방법에 대해 설명하는이 기사를 찾았습니다. 템플릿 으로 Subject / Observer 패턴 구현 . 이것은 당신이 인수를 템플릿 할 수 있는지 궁금해했습니다.

인수를 템플릿 화하는 방법에 대한이 스택 오버플로 질문을 발견했습니다. 템플릿 기반 주제 관찰자 패턴-static_cast 또는 dynamic_cast 사용해야 합니다. 그러나 OP에는 아무도 대답하지 않은 문제가있는 것 같습니다.

내가 할 수있는 다른 일은 다음과 같이 Update 메소드를 변경하여 EventArg 객체를 가져 오는 것입니다.

void MyClass::Update(Subject *subject, EventArg arg)
{
  ...

그런 다음 특정 인수 데이터에 대해 EventArg의 하위 클래스를 만든 다음 업데이트 메소드 내의 특정 하위 클래스로 다시 캐스트합니다.

업데이트 2

또한 비동기 메시지 기반 c ++ 프레임 워크 작성 기사를 찾았습니다 . 2 부 제목을 가진 나와있는가에 대한 세부 정보 통신 무엇을 변경합니다.

나는 Boost.Signals 사용을 진지하게 고려하고 있습니다 . 내 자신의 옵저버 패턴을 사용하는 것이 간단했을 때 의미가 있었지만 타입과 템플릿을 템플릿 화하는 것은 복잡해지기 시작했습니다. 그리고 Boost.Signals2의 스레드 안전성이 필요할 수 있습니다.

업데이트 3

또한 관찰자 패턴에서 흥미로운 기사를 발견했습니다.

Herb Sutter에 의한 관찰자 일반화

C ++에서 관찰자 패턴 구현-1 부

관찰자 디자인 패턴 구현 경험 (2 부)

관찰자 디자인 패턴 구현 경험 (3 부)

그러나 Boost.Signals를 사용하여 구현을 전환했지만 아마도 내 목적으로 부풀어 오를 수 있지만 성공적으로 작동합니다. 그리고 아마도 팽창이나 속도에 대한 우려는 무의미합니다.


본문의 질문이 실제로 제목과 일치하지 않는 것 같습니다. 질문의 핵심은 무엇입니까?
Nicole

@Renesis : 현재 게시물 시작 부분의 코드 샘플에서와 같이 Observer 패턴을 사용하고 있습니다. 현재 작업중 인 코드의 경우 변경 사항을 구체적으로 알아야 그에 따라 반응 할 수 있습니다. 현재 관찰자 패턴 (표준)은이 정보를 제공하지 않습니다. 내 질문은 변경된 내용에 대한 정보를 가장 잘 얻는 방법입니다.
사용자

@Renesis : 여기에 비슷한 질문을하는 포럼 스레드가 있습니다 : gamedev.net/topic/497105-observer-pattern
사용자

광고 업데이트 2 : Boost.Signals 사용을 확실히 지원합니다. 자신의 롤링보다 훨씬 편리합니다. 이 작업을 위해 더 가벼운 것을 원한다면 libsigc ++ 도 있습니다 (Boost.Signals는 나머지 Boost의 많은 코드를 사용합니다). 그래도 스레드 안전하지 않습니다.
Jan Hudec

속도 문제와 관련하여 : Boost.Signals가 얼마나 빠른지 잘 모르겠지만, 엄청난 양의 이벤트가 발생하는 경우에만 문제가됩니다.
Max

답변:


4

여부 C ++ 또는 JAVA는 관찰자에 통지 할 수 의 정보와 함께 올 것을 변경됩니다. 동일한 방법으로 notifyObservers (Object arg)를 C ++에서도 사용할 수 있습니다.

일반적으로 문제는 하나 이상의 관찰자에게 여러 명의 주체가 파견 class arg될 수 있으므로 하드 코딩 될 수 없다는 문제가 남아 있습니다.

일반적으로 가장 좋은 방법은 다양한 클래스에 대해 동일한 데이터 유형을 형성하지만 관찰 된 클래스에 따라 값이 다른 일반 메시지 / 토큰 형식으로 인수를 작성하는 것입니다. 또는 이러한 모든 알림 값이 모든 클래스 클래스에서 파생되며 모든 클래스에 공통입니다.

관찰자 패턴, 이다 의 Arg 데이터 유형은 하드 observee과 관찰자 사이에 코딩되지 않는 것이 중요합니다 - 그렇지 않으면이 발전하기 어려운 일을하게하는 커플 링입니다.

편집
관찰자가 관찰 한 것뿐만 아니라 변경된 내용을 기반으로 다른 많은 작업을 수행해야하는 경우 방문자 패턴을 확인할 수도 있습니다 . 방문자 패턴에서 관찰자 / 방문자는 수정 된 오브젝트를 호출 하므로 수정이 무엇인지 알 수있을뿐만 아니라 실제로 작업 할 수 있습니다.


5
관찰자가 인수를 해석하는 경우가 있다 커플 링, 당신은 유형을 숨기는 방법에 상관없이. 사실 나는 말하고 싶지만 당신이 통과하면 진화하기 어려운 Object( void *, boost::any또는 무언가 유사하게 일반)은 일반 유형하면서, 때문에 당신이 뭔가가 변경된 것을 컴파일시에 볼 수 있습니다 특정 유형, 특정 유형을 통과하는 것보다 그것을 관찰자가 전달 된 실제 데이터로 작업 할 수 없으므로 컴파일 및 작동이 중지됩니다.
Jan Hudec

@ JanHudec : 나는 그것에 동의하지만, 그것은 당신이 각 인수 (즉, 각 유스 케이스)에 대해 특정 일회성 관찰자 / 주제 서브 클래스를 설정한다는 것을 의미합니까?
사용자

@ JanHudec : 또한 커플 링은 한 가지 방법입니다. 대상은 관찰자에 대해 전혀 모른다. 그렇습니다. 관찰자는 주제에 대해 알고 있지만 관찰자 패턴이 작동하는 방식이 아닙니까?
사용자

1
@User : 예, 각 주제에 대해 특정 인터페이스를 만들고 각 관찰자는 관찰해야하는 주제의 인터페이스를 구현합니다. 글쎄, 내가 사용하는 모든 언어는 언어 또는 프레임 워크 (C # 대리자, C ++ 11 std::functionBoost boost::function, Gtk + GClosure, python 바운드 메소드 등)에 메소드 포인터를 바인딩 했으므로 적절한 서명으로 메소드를 정의하고 실제 시스템을 작성하도록 요청하십시오. 관찰자. 커플 링은 실제로 한 가지 방법 일 뿐이며 주제는 관찰자를위한 인터페이스를 정의하지만 구현에 대한 아이디어는 없습니다.
Jan Hudec

0

C ++에서 "Java Like"일반 이벤트 인수를 전송하는 몇 가지 방법이 있습니다.

1) 이벤트 인수를 void *로 선언하고 이벤트 핸들러에서 올바른 클래스로 캐스트하십시오.

2) 이벤트 인수를 (예 :)에 대한 새로운 클래스 / 인터페이스에 대한 포인터 / 참조로 선언하십시오.

class GenericEventArgument
{
  virtual bool didAction1Happen() = 0;
  virtual int getActionInteger() = 0;
};

실제 이벤트 인수 클래스가이 클래스에서 파생되도록합니다.

템플릿 기반 옵저버 체크 아웃에 관한 질문은

http://www.codeproject.com/Articles/3267/Implementing-a-Subject-Observer-pattern-with-templ


-1

나는 이것이 정식 이름인지 알지 못하지만, 나는 스몰 토크 시절부터 관찰 가능 항목에서 변경된 사항을 식별하기 위해 "종횡비"라는 용어를 기억합니다.

EventArg (및 서브 클래 싱)에 대한 아이디어만큼 복잡하지는 않습니다. 그것은 관찰 가능에서 관찰자로 문자열 (정수 상수 일 수도 있음)을 전달합니다.

플러스 :이 두 간단한 방법이 있습니다 ( update(observable)updateAspect(observable, aspect)

빼기 : 관찰자는 관찰자에게 추가 정보를 요청해야 할 수도 있습니다 (예 : "정수").

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