2013-06-10 3 views
11

Tutto quello che sto cercando di fare è implementare il pattern di osservatore.IObserver e IObservable in C# per Observer vs Delegates, Events

Quindi, mi si avvicinò con questa soluzione:

Abbiamo un PoliceHeadQuarters il cui compito principale è quello di inviare le notifiche a tutti coloro che sono iscritti ad esso. Considera che le classi DSP, Inspector e SubInspector sono sottoscritte a PoliceHeadQuarters.

Uso Eventi e delegati ho scritto

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())); 
    } 
} 

e in questo modo ho invocato lo

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

così, sia l'ispettore e classi SubInspector avere la notifica ogni volta che c'è invocato la RaiseANotification funzione di().

Sembra che DotNet Framework 4, 4.5 supporti un nuovo metodo denominato IObserver e IObservable.

Qualcuno può darmi un esempio semplicissimo usando il pattern IObservable e IObserver per lo scenario sopra? Ho cercato solo su Google per trovare gli esempi disponibili in Internet troppo gonfiati e difficili da capire.

mio Hinch: (probabilmente penso che sia sbagliato)

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

Grazie in anticipo.

MODIFICA: qualcuno ha anche affermato che la documentazione MSDN non è corretta per IObservable @ IObservable vs Plain Events or Why Should I use IObservable?.

+0

http://msdn.microsoft.com/en-us/library/dd990377.aspx - c'è un bell'esempio, perché non provi a compilarlo ed eseguirlo? – Spook

+0

@Spook: il problema è in realtà non posso co-relazionare il mio scenario con quegli esempi. Qualsiasi struttura di codice skeleton dovrebbe aiutarmi ad andare oltre .. –

+0

Sembra che l'esempio di Microsoft stia utilizzando un Aggregatore di eventi di base. Un approccio più complesso ma, in definitiva, più flessibile. L'Aggregator esegue iterazioni sui tipi di IObserver chiamandoli in sequenza.Penso che questo sia il motivo per cui l'approccio basato sull'interfaccia è usato in contrasto con i delegati. –

risposta

25

Ecco una modifica del MSDN esempio per adattare il vostro quadro:

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

Se l'ispettore ha catturato il professore o no, ora dovrei essere in grado di catturare il modello. Grazie molto. –

+2

Contento di aver potuto aiutare. In bocca al lupo! – Spook

+0

La cosa buona è che il GC .Net può gestire riferimenti circolari o questo codice potrebbe perdere di vista. – Pharap

15

Un altro suggerimento - probabilmente si desidera prendere in considerazione sfruttando la libreria di estensioni reattivi per qualsiasi codice utilizzando IObservable. Il pacchetto nuget è Rx-Main e la homepage è qui: http://msdn.microsoft.com/en-us/data/gg577609.aspx

Ciò consente di risparmiare un gran numero di codice. Ecco un esempio super semplice:

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!"); 

Sarà uscita:

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

estensioni reattiva è un grande soggetto, e una biblioteca molto potente - vale la pena indagare. Raccomando il laboratorio pratico dal link sopra.

Probabilmente vorrai incorporare quelle sottoscrizioni all'interno del tuo Inspector, immplementatinos di SubInspector per riflettere più da vicino il tuo codice. Ma spero che questo ti dia un'idea di cosa puoi fare con Rx.

+0

Grazie per Rx. Andrà approfondito .. –