답변:
관찰자 패턴은 일반적으로 이벤트로 구현됩니다. .
예를 들면 다음과 같습니다.
using System;
class Observable
{
public event EventHandler SomethingHappened;
public void DoSomething() =>
SomethingHappened?.Invoke(this, EventArgs.Empty);
}
class Observer
{
public void HandleEvent(object sender, EventArgs args)
{
Console.WriteLine("Something happened to " + sender);
}
}
class Test
{
static void Main()
{
Observable observable = new Observable();
Observer observer = new Observer();
observable.SomethingHappened += observer.HandleEvent;
observable.DoSomething();
}
}
자세한 내용은 링크 된 기사를 참조하십시오.
위의 예는 C # 6 null 조건부 연산자를 사용하여 구독하지 않은 DoSomething
경우를 처리하기 위해 안전하게 구현 SomethingHappened
하므로 null입니다. 이전 버전의 C #을 사용하는 경우 다음과 같은 코드가 필요합니다.
public void DoSomething()
{
var handler = SomethingHappened;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
SomethingHappened = null
나중에 설정할 수 있습니다 (모든 핸들러를 구독 취소하는 게으르고 비 이상적 인 경우 편리함). 항체 검사는 항상 필요합니다.
SomethingHappened?.Invoke(this, EventArgs.Empty);
다음은 간단한 예입니다.
public class ObservableClass
{
private Int32 _Value;
public Int32 Value
{
get { return _Value; }
set
{
if (_Value != value)
{
_Value = value;
OnValueChanged();
}
}
}
public event EventHandler ValueChanged;
protected void OnValueChanged()
{
if (ValueChanged != null)
ValueChanged(this, EventArgs.Empty);
}
}
public class ObserverClass
{
public ObserverClass(ObservableClass observable)
{
observable.ValueChanged += TheValueChanged;
}
private void TheValueChanged(Object sender, EventArgs e)
{
Console.Out.WriteLine("Value changed to " +
((ObservableClass)sender).Value);
}
}
public class Program
{
public static void Main()
{
ObservableClass observable = new ObservableClass();
ObserverClass observer = new ObserverClass(observable);
observable.Value = 10;
}
}
노트 :
이 모델에는 논리를 수행하고 "이벤트"를 게시 할 게시자가 있습니다.
그런 다음 게시자는 특정 이벤트를 받도록 구독 한 구독자에게만 이벤트를 보냅니다.
C #에서 모든 개체는 다른 응용 프로그램이 구독 할 수있는 이벤트 집합을 게시 할 수 있습니다.
게시 클래스에서 이벤트가 발생하면 구독 한 모든 응용 프로그램에 알립니다.
다음 그림은이 메커니즘을 보여줍니다.
C #의 이벤트 및 대리인에 대해 가능한 가장 간단한 예 :
코드는 설명이 필요 없으며 코드를 정리하기 위해 주석을 추가했습니다.
using System;
public class Publisher //main publisher class which will invoke methods of all subscriber classes
{
public delegate void TickHandler(Publisher m, EventArgs e); //declaring a delegate
public TickHandler Tick; //creating an object of delegate
public EventArgs e = null; //set 2nd paramter empty
public void Start() //starting point of thread
{
while (true)
{
System.Threading.Thread.Sleep(300);
if (Tick != null) //check if delegate object points to any listener classes method
{
Tick(this, e); //if it points i.e. not null then invoke that method!
}
}
}
}
public class Subscriber1 //1st subscriber class
{
public void Subscribe(Publisher m) //get the object of pubisher class
{
m.Tick += HeardIt; //attach listener class method to publisher class delegate object
}
private void HeardIt(Publisher m, EventArgs e) //subscriber class method
{
System.Console.WriteLine("Heard It by Listener");
}
}
public class Subscriber2 //2nd subscriber class
{
public void Subscribe2(Publisher m) //get the object of pubisher class
{
m.Tick += HeardIt; //attach listener class method to publisher class delegate object
}
private void HeardIt(Publisher m, EventArgs e) //subscriber class method
{
System.Console.WriteLine("Heard It by Listener2");
}
}
class Test
{
static void Main()
{
Publisher m = new Publisher(); //create an object of publisher class which will later be passed on subscriber classes
Subscriber1 l = new Subscriber1(); //create object of 1st subscriber class
Subscriber2 l2 = new Subscriber2(); //create object of 2nd subscriber class
l.Subscribe(m); //we pass object of publisher class to access delegate of publisher class
l2.Subscribe2(m); //we pass object of publisher class to access delegate of publisher class
m.Start(); //starting point of publisher class
}
}
산출:
청취자에게 들었습니다
Listener2에 의해 들었습니다
청취자에게 들었습니다
Listener2에 의해 들었습니다
청취자에게 들었습니다. . . (무한시)
위의 몇 가지 훌륭한 예를 함께 묶어 두었 습니다 (Skeet 과 Mr. Karlsen 에게 항상 감사합니다 ). 다른 Observable을 포함시키고 Observer에서 추적 할 수있는 인터페이스를 사용했습니다. 내부 목록을 통해 다수의 Observable을 "관찰"
namespace ObservablePattern
{
using System;
using System.Collections.Generic;
internal static class Program
{
private static void Main()
{
var observable = new Observable();
var anotherObservable = new AnotherObservable();
using (IObserver observer = new Observer(observable))
{
observable.DoSomething();
observer.Add(anotherObservable);
anotherObservable.DoSomething();
}
Console.ReadLine();
}
}
internal interface IObservable
{
event EventHandler SomethingHappened;
}
internal sealed class Observable : IObservable
{
public event EventHandler SomethingHappened;
public void DoSomething()
{
var handler = this.SomethingHappened;
Console.WriteLine("About to do something.");
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
internal sealed class AnotherObservable : IObservable
{
public event EventHandler SomethingHappened;
public void DoSomething()
{
var handler = this.SomethingHappened;
Console.WriteLine("About to do something different.");
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
internal interface IObserver : IDisposable
{
void Add(IObservable observable);
void Remove(IObservable observable);
}
internal sealed class Observer : IObserver
{
private readonly Lazy<IList<IObservable>> observables =
new Lazy<IList<IObservable>>(() => new List<IObservable>());
public Observer()
{
}
public Observer(IObservable observable) : this()
{
this.Add(observable);
}
public void Add(IObservable observable)
{
if (observable == null)
{
return;
}
lock (this.observables)
{
this.observables.Value.Add(observable);
observable.SomethingHappened += HandleEvent;
}
}
public void Remove(IObservable observable)
{
if (observable == null)
{
return;
}
lock (this.observables)
{
observable.SomethingHappened -= HandleEvent;
this.observables.Value.Remove(observable);
}
}
public void Dispose()
{
for (var i = this.observables.Value.Count - 1; i >= 0; i--)
{
this.Remove(this.observables.Value[i]);
}
}
private static void HandleEvent(object sender, EventArgs args)
{
Console.WriteLine("Something happened to " + sender);
}
}
}
C # 에서 델리게이트 및 이벤트와 함께 관찰자 패턴 을 적용하는 것은 약간 변형 된 MSDN 에 따라 "이벤트 패턴"으로 명명 됩니다.
이 기사에서는 고전적인 방법과 델리게이트 및 이벤트를 사용하여 C #에서 패턴을 적용하는 방법에 대한 잘 구성된 예를 찾을 수 있습니다.
public class Stock
{
//declare a delegate for the event
public delegate void AskPriceChangedHandler(object sender,
AskPriceChangedEventArgs e);
//declare the event using the delegate
public event AskPriceChangedHandler AskPriceChanged;
//instance variable for ask price
object _askPrice;
//property for ask price
public object AskPrice
{
set
{
//set the instance variable
_askPrice = value;
//fire the event
OnAskPriceChanged();
}
}//AskPrice property
//method to fire event delegate with proper name
protected void OnAskPriceChanged()
{
AskPriceChanged(this, new AskPriceChangedEventArgs(_askPrice));
}//AskPriceChanged
}//Stock class
//specialized event class for the askpricechanged event
public class AskPriceChangedEventArgs : EventArgs
{
//instance variable to store the ask price
private object _askPrice;
//constructor that sets askprice
public AskPriceChangedEventArgs(object askPrice) { _askPrice = askPrice; }
//public property for the ask price
public object AskPrice { get { return _askPrice; } }
}//AskPriceChangedEventArgs
/**********************Simple Example ***********************/
class Program
{
static void Main(string[] args)
{
Parent p = new Parent();
}
}
////////////////////////////////////////////
public delegate void DelegateName(string data);
class Child
{
public event DelegateName delegateName;
public void call()
{
delegateName("Narottam");
}
}
///////////////////////////////////////////
class Parent
{
public Parent()
{
Child c = new Child();
c.delegateName += new DelegateName(print);
//or like this
//c.delegateName += print;
c.call();
}
public void print(string name)
{
Console.WriteLine("yes we got the name : " + name);
}
}
추가 관찰자를 추가하기 위해 소스 코드를 변경하고 싶지 않았으므로 다음 간단한 예제를 작성했습니다.
//EVENT DRIVEN OBSERVER PATTERN
public class Publisher
{
public Publisher()
{
var observable = new Observable();
observable.PublishData("Hello World!");
}
}
//Server will send data to this class's PublishData method
public class Observable
{
public event Receive OnReceive;
public void PublishData(string data)
{
//Add all the observer below
//1st observer
IObserver iObserver = new Observer1();
this.OnReceive += iObserver.ReceiveData;
//2nd observer
IObserver iObserver2 = new Observer2();
this.OnReceive += iObserver2.ReceiveData;
//publish data
var handler = OnReceive;
if (handler != null)
{
handler(data);
}
}
}
public interface IObserver
{
void ReceiveData(string data);
}
//Observer example
public class Observer1 : IObserver
{
public void ReceiveData(string data)
{
//sample observers does nothing with data :)
}
}
public class Observer2 : IObserver
{
public void ReceiveData(string data)
{
//sample observers does nothing with data :)
}
}
이 같은:
// interface implementation publisher
public delegate void eiSubjectEventHandler(eiSubject subject);
public interface eiSubject
{
event eiSubjectEventHandler OnUpdate;
void GenereteEventUpdate();
}
// class implementation publisher
class ecSubject : eiSubject
{
private event eiSubjectEventHandler _OnUpdate = null;
public event eiSubjectEventHandler OnUpdate
{
add
{
lock (this)
{
_OnUpdate -= value;
_OnUpdate += value;
}
}
remove { lock (this) { _OnUpdate -= value; } }
}
public void GenereteEventUpdate()
{
eiSubjectEventHandler handler = _OnUpdate;
if (handler != null)
{
handler(this);
}
}
}
// interface implementation subscriber
public interface eiObserver
{
void DoOnUpdate(eiSubject subject);
}
// class implementation subscriber
class ecObserver : eiObserver
{
public virtual void DoOnUpdate(eiSubject subject)
{
}
}