이벤트와 델리게이트 간의 관계가 복합 패턴을 채택한다고 말할 수 있습니까?
이벤트는를 사용하여 정의 된 많은 핸들러를 포함 할 수 있습니다. delegate
현재 제가 이해하는 것은 델리게이트가 함수 포인터의 추상화 일 뿐이라는 것입니다. 때문에 event
하는과 관련된 어떤 delegate
아이디어가되도록 복합 패턴 취급을 복합 오브젝트 단말 객체와 같은 타입 / 추가 그것에 많은 대리자를 제거하고 :
composite.onTriggered();
// Internally:
// foreach(handler in composite)
// {
// handler.onTriggered();
// }
에서 관리하는 모든 핸들러를 차례로 호출합니다 composite
.
하지만 public event EventHandler ThresholdReached
복합을 정의하지 않는 것 같습니다. 아래 코드의 내 의견을 참조하십시오.
class Counter
{
public event EventHandler ThresholdReached;
protected virtual void OnThresholdReached(EventArgs e)
{
EventHandler handler = ThresholdReached; // So what's the point of this line?
handler?.Invoke(this, e);
// Why not just:
// ThresholdReached?.Invoke(this, e);
}
// provide remaining implementation for the class
}
추상적 인 수준의 아이디어가 맞습니까? 정정을 제공 할 수 없다면?
답변
귀하의 질문에 직접 대답하면 다음과 같습니다. 아니요, 이벤트와 복합 패턴을 채택한 대리자 간에는 관계가 없습니다 . 대표 디자인 예 , 복합 패턴을 따릅니다. 이벤트가 아닙니다 . (또한, 델리게이트를 활용하기 위해 이벤트가 필요하지 않습니다. (아래 참조 DelegateBased
)) ( 끝 부분 에 " 그래서이 라인의 요점은 무엇입니까? "에 대한 귀하의 의견에 사이드 노트로 답변하겠습니다. )
그럼에도 불구하고 Delegate 유형 자체는“ 복합 패턴 은 동일한 유형의 개체 의 단일 인스턴스 와 동일한 방식으로 처리되는 개체 그룹을 설명 합니다. ”.
차례로 @ Flydog57 및 @ mark-seemann이 이미 언급했듯이 .NET 이벤트 모델은 관찰자 패턴을 따릅니다 .
이벤트 및 대리자 사이의 관계는 안부 이벤트 선언 이 필요할 수 있습니다 대리자 형식을합니다 ( TypeSpec
이 섹션에 명시된대로를) II.18 정의 이벤트 의 VI에 ECMA-335 (CLI) 파티션 I (표준) :
일반적인 사용에서 TypeSpec (있는 경우)은 서명이 이벤트의 fire 메서드에 전달 된 인수와 일치하는 대리자를 식별합니다.
그것은 명확하게하려면 다음 두 가지 동등한 예 확인 EventBased
용도의 대리자 필드없이 이벤트 및 DelegateBased
사용 이벤트없이 위임 필드를 . 내가 명백하게 delegate field 또는 delegate type 이라고 말하는 것을 주목하십시오 . 그들은 동일하지 않습니다. 두 예제 모두이 예제 에서 다음과 같이 선언 된 대리자 형식 이 필요합니다 .
delegate void Observer();
다음과 같이 두 가지 예를 모두 실행할 수 있습니다.
var subject = new DelegateBased(); // replace it with: var subject = new EventBased();
Observer foo = () => Console.Write("Foo");
Observer bar = () => Console.Write("Bar");
subject.RegisterObserver(foo); // subject.Caller += foo;
subject.RegisterObserver(bar); // subject.Caller += bar;
subject.Notify(); // prints: FooBar
Console.WriteLine();
subject.UnregisterObserver(foo); // subject.Caller -= foo;
subject.Notify(); // prints: Bar
다음 으로 Wikipedia 의 Observer Pattern 예제에 따라 이름을 사용 하는 EventBased
및 의 두 구현DelegateBased
class EventBased {
private List<Observer> observers = new List<Observer>();
public event Observer Caller {
add { RegisterObserver(value); }
remove { UnregisterObserver(value); }
}
public void Notify() { foreach (var caller in observers) caller(); }
public void RegisterObserver(Observer val) { observers.Add(val); }
public void UnregisterObserver(Observer val) { observers.Remove(val); }
}
class DelegateBased {
private Observer observers; // delegate field without events
public void Notify() { observers(); }
public void RegisterObserver(Observer val) {
observers = (Observer) Delegate.Combine(observers, val); // <=> observers += val
}
public void UnregisterObserver(Observer val) {
observers = (Observer) Delegate.Remove(observers, val); // <=> observers -= val
}
}
다음에 대한 귀하의 의견과 관련하여 :
EventHandler handler = ThresholdReached; // So what's the point of this line?
handler?.Invoke(this, e);
Jeffrey Richter가 "C #을 통한 Clr"의 걸작 인 Chapter 11-Events at " Raising an Event in a Thread-Safe Way " 에서 명확하게 식별 한 이유는 다음 NewMail
과 ThresholdReached
같습니다.
의 문제
OnNewMail
방법은 스레드가 볼 수 있다는 것입니다NewMail
null는 아니고, 다음, 바로 호출하기 전에NewMail
, 다른 스레드가 체인 결정에서 대리자를 제거 할 수NewMail
null
A의 결과로NullReferenceException
발생된다.
Flydog57이 지적했듯이 .NET 이벤트 모델은 기본적으로 언어에 내장 된 Observer 패턴 IEnumerable
이며 foreach
Iterator 패턴 과 마찬가지로 구현합니다.
그러나 Gang of Four 책의 패턴은 다양한 추상화 수준에 있습니다. 나는 이것이 1994 년에 누구에게도 분명하다고 확신하지 못하지만, 수십 년 동안 사용함에 따라 이러한 패턴 중 일부가 다른 패턴보다 더 일반적이라는 것이 점점 더 명확 해지고 있습니다. 그러한 패턴 중 하나는 장식 자 패턴을 퇴화 전문화로 볼 수있는 어댑터 패턴입니다.
또 다른 패턴은 Composite입니다. 책의 다른 패턴 중 일부는 Composite의 전문화로 볼 수 있습니다. Observer뿐만 아니라 Command and State (적어도 책에 설명 된대로); 아마도 다른.
직감이 맞다고 생각합니다. 이벤트는 관찰자 패턴 이후에 가장 구체적으로 패턴 화되지만이를 합성물로 생각할 수도 있습니다. .NET 이벤트 대신 Rx (Reactive Extensions) 및 IObserver
보다 일반적으로 모노 이드를 생성하는 모든 API는 Composite로 모델링 할 수 있습니다 . 이벤트는 데이터를 반환하지 않으므로 ( void
메서드 서명이 있음) 모노 이드를 형성합니다. 따라서 복합 디자인 패턴의 인스턴스로 볼 수도 있습니다.