following the answer I got from t3chb0t last time
News-reading application using the Observer pattern
and also following the example here
https://msdn.microsoft.com/en-us/library/dd990377(v=vs.110).aspx
I implemented a the answer to the following question
Design a kind of kindle fire application where we can subscribe NewsChannel channel and read the NewsChannel from all publishers as a digital format.
Please comment on the implementation of the design pattern observer and the code style. you can ignore the unit test it is just for understanding how to use the code. Thanks
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace DesignPatternsQuestions
{
/// <summary>
/// Design a kind of kindle fire application where we can subscribe
/// NewsChannel channel and read the NewsChannel from all publishers as a digital format.
/// </summary>
[TestClass]
public class ObserverPatternTest
{
[TestMethod]
public void ObeserverPatternTest()
{
NewsChannel newsChannel1 = new NewsChannel();
NewsChannel newsChannel2 = new NewsChannel();
KindleApp kindle = new KindleApp();
kindle.Subscribe(newsChannel1);
kindle.Subscribe(newsChannel2);
newsChannel1.SendMessage(new Image(1920, 1080));
newsChannel2.SendMessage(new TextMessage("News Channel 2"));
newsChannel1.EndMessages();
newsChannel1.SendMessage(new TextMessage("News Channel 1 done"));
}
}
public interface IMessage
{
string Print();
}
public class TextMessage : IMessage
{
private readonly string _text;
public TextMessage(string text)
{
_text = text;
}
public string Print()
{
return _text;
}
}
public class Image : IMessage
{
private readonly uint _width;
private readonly uint _height;
public Image(uint width, uint height )
{
_width = width;
_height = height;
}
public string Print()
{
return string.Format("Image width:{0} height {1}", _width, _height);
}
}
/// <summary>
/// this class handles all of the different observers, observers listen to IObservables..
/// </summary>
/// <typeparam name="T"></typeparam>
public class NewsChannel : IObservable<IMessage>
{
private readonly List<IObserver<IMessage>> _observers;
public NewsChannel()
{
_observers = new List<IObserver<IMessage>>();
}
public IDisposable Subscribe(IObserver<IMessage> observer)
{
if (!_observers.Contains(observer))
{
_observers.Add(observer);
}
return new Unsubscriber<IMessage>(_observers, observer);
}
/// <summary>
/// send a message of certain type to all of the observers
/// </summary>
/// <param name="message"></param>
public void SendMessage(IMessage message)
{
foreach (var observer in _observers)
{
if (message != null)
{
observer.OnNext(message);
}
else
{
observer.OnError(new ArgumentNullException());
}
}
}
public void EndMessages()
{
foreach (var observer in _observers)
{
observer.OnCompleted();
}
_observers.Clear();
}
}
/// <summary>
/// this also can be a private class inside the NewsChannel class
/// </summary>
/// <typeparam name="T"></typeparam>
public class Unsubscriber<T> : IDisposable
{
private List<IObserver<T>> _observers;
private IObserver<T> _observer;
public Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (_observer != null && _observers.Contains(_observer))
{
_observers.Remove(_observer);
}
}
}
public class KindleApp : IObserver<IMessage>
{
private IDisposable _unsubscriber;
public virtual void Subscribe(IObservable<IMessage> provider)
{
if (provider != null)
{
_unsubscriber = provider.Subscribe(this);
}
}
public virtual void Unsubscribe()
{
_unsubscriber.Dispose();
}
//print the message
public void OnNext(IMessage value)
{
Console.WriteLine(value.Print());
}
public void OnError(Exception error)
{
Console.WriteLine("can't handle error");
}
public void OnCompleted()
{
Console.WriteLine("on complete");
this.Unsubscribe();
}
}
}