2013-06-10 5 views
11

Wszystko, co próbuję zrobić, to implementacja wzorca obserwatora.IObserver i IObservable w języku C# dla obserwatora kontra uczestnicy, zdarzenia

Więc wymyśliłem tego rozwiązania:

Mamy PoliceHeadQuarters, których głównym zadaniem jest wysyłanie powiadomień do wszystkich tych, którzy są zapisani do niego. Weź pod uwagę, że klasy DSP, Inspector i SubInspector zasubskrybowały usługę PoliceHeadQuarters.

Korzystanie Imprezy i Delegaci pisałem

public class HeadQuarters 
{ 
    public delegate void NewDelegate(object sender, EventArgs e); 
    public event EventHandler NewEvent; 
    public void RaiseANotification() 
    { 
     var handler = this.NewEvent; 
     if (handler != null) 
     { 
      handler(this, new EventArgs()); 
     } 
    } 
} 

public class SubInspector 
{ 
    public void Listen(object sender, EventArgs e) 
    { 
     MessageBox.Show(string.Format("Event Notification received by sender = {0} with eventArguments = {1}", sender, e.ToString())); 
    } 
} 

public class Inspector 
{ 
    public void Listen(object sender, EventArgs e) 
    { 
     MessageBox.Show(string.Format("Event Notification received by sender = {0} with eventArguments = {1}", sender, e.ToString())); 
    } 
} 

i to w jaki sposób powołać go

 var headQuarters = new HeadQuarters(); 
     var SubInspector = new SubInspector(); 
     var Inspector = new Inspector(); 
     headQuarters.NewEvent += Inspector.Listen; 
     headQuarters.NewEvent += SubInspector.Listen; 
     headQuarters.RaiseANotification(); 

więc, zarówno Inspector i zajęcia SubInspector dostać powiadomienie, gdy tam RaiseANotification function() jest wywoływana.

Wygląda na to, że DotNet Framework 4, 4.5 obsługuje nowy sposób o nazwie IObserver i IObservable.

Czy ktoś może dać mi super prosty przykład używając wzoru IObservable i IObserver dla powyższego scenariusza? Szukałem go tylko po to, aby znaleźć dostępne w internecie przykłady, które są zbyt rozdęte i trudne do zrozumienia.

My Hinch: (prawdopodobnie myślę, że to źle)

class DSP : IObserver //since it observes the headquarters ? 
    class PoliceHeadQuarters: IObservable // since here's where we send the notifications ? 

góry dzięki.

EDYCJA: Ktoś powiedział również, że dokumentacja MSDN jest również niepoprawna dla IObservable @ IObservable vs Plain Events or Why Should I use IObservable?.

+0

http://msdn.microsoft.com/en-us/library/dd990377.aspx - istnieje niezły przykład, dlaczego nie spróbujesz go skompilować i uruchomić? – Spook

+0

@Spook: Problem polega na tym, że nie mogę powiązać mojego scenariusza z tymi przykładami. Jakakolwiek struktura kodu szkieletowego powinna pomóc mi pójść dalej. –

+0

Wygląda na to, że przykład Microsoftu wykorzystuje podstawowy moduł Event Aggregator. Bardziej złożone, ale ostatecznie bardziej elastyczne podejście. Agregator iteruje nad typami IObserver wywołującymi je w sekwencji.Myślę, że właśnie dlatego stosuje się podejście oparte na interfejsie w przeciwieństwie do delegatów. –

Odpowiedz

25

Oto modyfikacja przykład MSDN, aby pasowały do ​​ramy:

public struct Message 
    { 
     string text; 

     public Message(string newText) 
     { 
      this.text = newText; 
     } 

     public string Text 
     { 
      get 
      { 
       return this.text; 
      } 
     } 
    } 

    public class Headquarters : IObservable<Message> 
    { 
     public Headquarters() 
     { 
      observers = new List<IObserver<Message>>(); 
     } 

     private List<IObserver<Message>> observers; 

     public IDisposable Subscribe(IObserver<Message> observer) 
     { 
      if (!observers.Contains(observer)) 
       observers.Add(observer); 
      return new Unsubscriber(observers, observer); 
     } 

     private class Unsubscriber : IDisposable 
     { 
      private List<IObserver<Message>> _observers; 
      private IObserver<Message> _observer; 

      public Unsubscriber(List<IObserver<Message>> observers, IObserver<Message> observer) 
      { 
       this._observers = observers; 
       this._observer = observer; 
      } 

      public void Dispose() 
      { 
       if (_observer != null && _observers.Contains(_observer)) 
        _observers.Remove(_observer); 
      } 
     } 

     public void SendMessage(Nullable<Message> loc) 
     { 
      foreach (var observer in observers) 
      { 
       if (!loc.HasValue) 
        observer.OnError(new MessageUnknownException()); 
       else 
        observer.OnNext(loc.Value); 
      } 
     } 

     public void EndTransmission() 
     { 
      foreach (var observer in observers.ToArray()) 
       if (observers.Contains(observer)) 
        observer.OnCompleted(); 

      observers.Clear(); 
     } 
    } 

    public class MessageUnknownException : Exception 
    { 
     internal MessageUnknownException() 
     { 
     } 
    } 

    public class Inspector : IObserver<Message> 
    { 
     private IDisposable unsubscriber; 
     private string instName; 

     public Inspector(string name) 
     { 
      this.instName = name; 
     } 

     public string Name 
     { 
      get 
      { 
       return this.instName; 
      } 
     } 

     public virtual void Subscribe(IObservable<Message> provider) 
     { 
      if (provider != null) 
       unsubscriber = provider.Subscribe(this); 
     } 

     public virtual void OnCompleted() 
     { 
      Console.WriteLine("The headquarters has completed transmitting data to {0}.", this.Name); 
      this.Unsubscribe(); 
     } 

     public virtual void OnError(Exception e) 
     { 
      Console.WriteLine("{0}: Cannot get message from headquarters.", this.Name); 
     } 

     public virtual void OnNext(Message value) 
     { 
      Console.WriteLine("{1}: Message I got from headquarters: {0}", value.Text, this.Name); 
     } 

     public virtual void Unsubscribe() 
     { 
      unsubscriber.Dispose(); 
     } 
    } 

    public class Program 
    { 
     public static void Main(string[] args) 
     { 
      Inspector inspector1 = new Inspector("Greg Lestrade"); 
      Inspector inspector2 = new Inspector("Sherlock Holmes"); 

      Headquarters headquarters = new Headquarters(); 

      inspector1.Subscribe(headquarters); 
      inspector2.Subscribe(headquarters); 

      headquarters.SendMessage(new Message("Catch Moriarty!")); 
      headquarters.EndTransmission(); 

      Console.ReadKey(); 
     } 
    } 
+1

Niezależnie od tego, czy inspektor złapie Profesora, czy nie, powinienem już teraz uchwycić Wzór. Wielkie dzięki. –

+2

Cieszę się, że mogę pomóc. Powodzenia! – Spook

+0

Dobrze, że .Net GC może obsługiwać kołowe odwołania lub ten kod byłby nieszczelny jak diabli. – Pharap

15

Kolejna propozycja - to prawdopodobnie warto rozważyć wykorzystanie biblioteki reaktywne Rozszerzenia dla dowolnego kodu przy użyciu IObservable. Pakiet nuget to Rx-Main, a strona główna dla niego jest tutaj: http://msdn.microsoft.com/en-us/data/gg577609.aspx

To pozwoli Ci zaoszczędzić sporo kodu. Oto bardzo prosty przykład:

var hq = new Subject<string>(); 

var inspectorSubscription = hq.Subscribe(
    m => Console.WriteLine("Inspector received: " + m)); 

var subInspectorSubscription = hq.Subscribe(
    m => Console.WriteLine("Sub Inspector received: " + m)); 

hq.OnNext("Catch Moriarty!"); 

To wyświetli:

Inspector received: Catch Moriarty! 
Sub Inspector received: Catch Moriarty! 

Reactive Extensions to wielki temat, i to bardzo potężne biblioteki - warte zbadania. Polecam praktyczne laboratorium z linku powyżej.

Prawdopodobnie zechcesz osadzić te subskrypcje w swoim Inspektorze, imin ininektor, aby lepiej odzwierciedlać Twój kod. Ale mam nadzieję, że to daje ci wgląd w to, co możesz zrobić z Rx.

+0

Dzięki za Rx. Zrobię to dokładnie .. –

Powiązane problemy