Add stock example on Observer pattern
This commit is contained in:
@@ -38,9 +38,11 @@ namespace BehavioralPatterns
|
|||||||
|
|
||||||
MementoPatternExamples.Run();
|
MementoPatternExamples.Run();
|
||||||
|
|
||||||
|
Console.ReadKey();
|
||||||
|
|
||||||
ObserverPatternExamples.Run();
|
ObserverPatternExamples.Run();
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,6 @@ namespace CommandPattern
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GoToNextStep()
|
|
||||||
{
|
|
||||||
Console.ReadKey();
|
|
||||||
Console.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetPatternDescription()
|
public static string GetPatternDescription()
|
||||||
{
|
{
|
||||||
return @"Patttern description:
|
return @"Patttern description:
|
||||||
@@ -76,5 +70,11 @@ level undo/redo functionality, in practice this only works for simple examples,
|
|||||||
where all entities are at the same level. More details about undo can be seen at:
|
where all entities are at the same level. More details about undo can be seen at:
|
||||||
http://gernotklingler.com/blog/implementing-undoredo-with-the-command-pattern/";
|
http://gernotklingler.com/blog/implementing-undoredo-with-the-command-pattern/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void GoToNextStep()
|
||||||
|
{
|
||||||
|
Console.ReadKey();
|
||||||
|
Console.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using ObserverPattern.Twits;
|
using ObserverPattern.StockUpdateEvents;
|
||||||
|
using ObserverPattern.Twits;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -11,8 +12,66 @@ namespace ObserverPattern
|
|||||||
{
|
{
|
||||||
public static void Run()
|
public static void Run()
|
||||||
{
|
{
|
||||||
|
Console.WriteLine(GetDescription());
|
||||||
|
Console.WriteLine(GetActors());
|
||||||
|
Console.WriteLine(IsThisPubSub());
|
||||||
|
|
||||||
|
StockUpdateEventsExample stockExample = new StockUpdateEventsExample();
|
||||||
|
stockExample.RunSimple();
|
||||||
|
|
||||||
|
GoToNextStep();
|
||||||
|
Console.WriteLine("Same business logic using RX");
|
||||||
|
stockExample.RunReactive();
|
||||||
|
|
||||||
|
Console.WriteLine(GetLapsedLinstenerProblem());
|
||||||
|
|
||||||
ObservableTwitsExample obsTwits = new ObservableTwitsExample();
|
ObservableTwitsExample obsTwits = new ObservableTwitsExample();
|
||||||
obsTwits.Run();
|
obsTwits.Run();
|
||||||
|
|
||||||
|
GoToNextStep();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetDescription()
|
||||||
|
{
|
||||||
|
return @"
|
||||||
|
The observer pattern is a software design pattern in which an object, called the subject,
|
||||||
|
maintains a list of its dependents, called observers, and notifies them automatically of any state changes,
|
||||||
|
usually by calling one of their methods. ";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string IsThisPubSub()
|
||||||
|
{
|
||||||
|
return @"
|
||||||
|
Observer/Observable pattern is mostly implemented in a synchronous way,
|
||||||
|
i.e. the observable calls the appropriate method of all its observers when some event occurs.
|
||||||
|
The Publisher/Subscriber pattern is mostly implemented in an asynchronous way (using message queue).
|
||||||
|
In the Observer/Observable pattern, the observers are aware of the observable.
|
||||||
|
Whereas, in Publisher/Subscriber, publishers and subscribers don't need to know each other.
|
||||||
|
They simply communicate with the help of message queues.
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetActors()
|
||||||
|
{
|
||||||
|
return @"
|
||||||
|
Subject -> Notifies interested observers when an event occurs
|
||||||
|
Observer -> Registers to a subject, to be notified when a specific event happens
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static string GetLapsedLinstenerProblem()
|
||||||
|
{
|
||||||
|
return @"
|
||||||
|
The leak happens when a listener fails to unsubscribe from the publisher when it no longer needs to listen.
|
||||||
|
Consequently, the publisher still holds a reference to the observer which prevents it from being garbage collected
|
||||||
|
— including all other objects it is referring to — for as long as the publisher is alive, which could be until the end of the application.
|
||||||
|
This causes not only a memory leak, but also a performance degradation with an 'uninterested' observer receiving and acting on unwanted events";
|
||||||
|
}
|
||||||
|
private static void GoToNextStep()
|
||||||
|
{
|
||||||
|
Console.ReadKey();
|
||||||
|
Console.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/ObserverPattern/StockUpdateEvents/AaplObserver.cs
Normal file
29
src/ObserverPattern/StockUpdateEvents/AaplObserver.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ObserverPattern.StockUpdateEvents
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Observer
|
||||||
|
/// </summary>
|
||||||
|
public class AaplObserver
|
||||||
|
{
|
||||||
|
double? oldValue;
|
||||||
|
public AaplObserver(StockSubject stockObservable)
|
||||||
|
{
|
||||||
|
stockObservable.StockUpdated += (obj, e) => PrintNewValue(e.Stock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintNewValue(Stock stock)
|
||||||
|
{
|
||||||
|
if (stock.Name == "AAPL")
|
||||||
|
{
|
||||||
|
if (oldValue.HasValue)
|
||||||
|
Console.WriteLine("Apple price updated from {0} to {1}", oldValue, stock.Value);
|
||||||
|
else
|
||||||
|
Console.WriteLine("Apple has a new price, new value is: {0}", stock.Value);
|
||||||
|
|
||||||
|
oldValue = stock.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/ObserverPattern/StockUpdateEvents/LondonStockObserver.cs
Normal file
25
src/ObserverPattern/StockUpdateEvents/LondonStockObserver.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ObserverPattern.StockUpdateEvents
|
||||||
|
{
|
||||||
|
public class LondonStockObserver
|
||||||
|
{
|
||||||
|
double? oldValue;
|
||||||
|
public LondonStockObserver(StockSubject stockObservable)
|
||||||
|
{
|
||||||
|
stockObservable.StockUpdated += (obj, e) => PrintStockValue(e.Stock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintStockValue(Stock stock)
|
||||||
|
{
|
||||||
|
if (stock.Name == "FTSE")
|
||||||
|
{
|
||||||
|
if (oldValue.HasValue)
|
||||||
|
Console.WriteLine("The Financial Times Stock Exchange 100 Index price updated from {0} to {1}", oldValue, stock.Value);
|
||||||
|
else
|
||||||
|
Console.WriteLine("The Financial Times Stock Exchange 100 Index has a new price, new value is: {0}", stock.Value);
|
||||||
|
oldValue = stock.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/ObserverPattern/StockUpdateEvents/Stock.cs
Normal file
10
src/ObserverPattern/StockUpdateEvents/Stock.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace ObserverPattern.StockUpdateEvents
|
||||||
|
{
|
||||||
|
public class Stock
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int Quantity { get; set; }
|
||||||
|
|
||||||
|
public double Value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/ObserverPattern/StockUpdateEvents/StockSubject.cs
Normal file
18
src/ObserverPattern/StockUpdateEvents/StockSubject.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ObserverPattern.StockUpdateEvents
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Subject
|
||||||
|
/// </summary>
|
||||||
|
public class StockSubject
|
||||||
|
{
|
||||||
|
|
||||||
|
public void UpdateStockValue(Stock s)
|
||||||
|
{
|
||||||
|
StockUpdated?.Invoke(this, new StockUpdateEventArgs(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<StockUpdateEventArgs> StockUpdated;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace ObserverPattern.StockUpdateEvents
|
||||||
|
{
|
||||||
|
public class StockUpdateEventArgs
|
||||||
|
{
|
||||||
|
public Stock Stock { get; set; }
|
||||||
|
|
||||||
|
public StockUpdateEventArgs(Stock stock)
|
||||||
|
{
|
||||||
|
Stock = stock;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ObserverPattern.StockUpdateEvents
|
||||||
|
{
|
||||||
|
public class StockUpdateEventsExample
|
||||||
|
{
|
||||||
|
public void RunSimple()
|
||||||
|
{
|
||||||
|
StockSubject stockSubject = new StockSubject();
|
||||||
|
|
||||||
|
LondonStockObserver londonObserver = new LondonStockObserver(stockSubject);
|
||||||
|
|
||||||
|
AaplObserver aaplObserver = new AaplObserver(stockSubject);
|
||||||
|
|
||||||
|
PublishUpdateStocks(stockSubject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunReactive()
|
||||||
|
{
|
||||||
|
StockSubject stockSubject = new StockSubject();
|
||||||
|
|
||||||
|
var londonObserver = Observable.FromEventPattern<StockUpdateEventArgs>(
|
||||||
|
ev => stockSubject.StockUpdated += ev,
|
||||||
|
ev => stockSubject.StockUpdated -= ev).Where(s => s.EventArgs.Stock.Name == "FTSE");
|
||||||
|
|
||||||
|
var aaplObserver = Observable.FromEventPattern<StockUpdateEventArgs>(
|
||||||
|
ev => stockSubject.StockUpdated += ev,
|
||||||
|
ev => stockSubject.StockUpdated -= ev).Where(s => s.EventArgs.Stock.Name == "AAPL");
|
||||||
|
|
||||||
|
using (londonObserver.Subscribe(PrintLondonStockPriceUpdate))
|
||||||
|
using (aaplObserver.Subscribe(PrintAaplStockPriceUpdate))
|
||||||
|
{
|
||||||
|
PublishUpdateStocks(stockSubject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintAaplStockPriceUpdate(EventPattern<StockUpdateEventArgs> eventP)
|
||||||
|
{
|
||||||
|
Console.WriteLine("apple updated, new value: {0}", eventP.EventArgs.Stock.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrintLondonStockPriceUpdate(EventPattern<StockUpdateEventArgs> eventP)
|
||||||
|
{
|
||||||
|
Console.WriteLine("london stock updated, new value: {0}", eventP.EventArgs.Stock.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PublishUpdateStocks(StockSubject stockSubject)
|
||||||
|
{
|
||||||
|
stockSubject.UpdateStockValue(new Stock { Name = "AAPL", Value = 3 });
|
||||||
|
stockSubject.UpdateStockValue(new Stock { Name = "AAPL", Value = 4 });
|
||||||
|
stockSubject.UpdateStockValue(new Stock { Name = "AAPL", Value = 5 });
|
||||||
|
stockSubject.UpdateStockValue(new Stock { Name = "AAPL", Value = 6 });
|
||||||
|
|
||||||
|
stockSubject.UpdateStockValue(new Stock { Name = "FTSE", Value = 6 });
|
||||||
|
stockSubject.UpdateStockValue(new Stock { Name = "FTSE", Value = 12 });
|
||||||
|
stockSubject.UpdateStockValue(new Stock { Name = "FTSE", Value = 2 });
|
||||||
|
stockSubject.UpdateStockValue(new Stock { Name = "FTSE", Value = 3 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,16 +11,16 @@ namespace ObserverPattern.Twits
|
|||||||
{
|
{
|
||||||
TwitObservable observable = new TwitObservable();
|
TwitObservable observable = new TwitObservable();
|
||||||
|
|
||||||
TwitUser t100 = new TwitUser("t100", observable);
|
using (TwitUser t100 = new TwitUser("t100", observable))
|
||||||
TwitUser r2d2 = new TwitUser("R2-D2", observable);
|
using (TwitUser r2d2 = new TwitUser("R2-D2", observable))
|
||||||
|
{
|
||||||
|
t100.Twit("El chupacapra - BOOM BOOM");
|
||||||
|
|
||||||
t100.Twit("El chupacapra - BOOM BOOM");
|
r2d2.Twit("Vamos vamos mi amor");
|
||||||
|
|
||||||
r2d2.Twit("Vamos vamos mi amor");
|
observable.ItsGoingHomeTime();
|
||||||
|
}
|
||||||
t100.Dispose();
|
|
||||||
|
|
||||||
observable.ItsGoingHomeTime();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace ObserverPattern.Twits
|
|||||||
if (!observers.Contains(observer))
|
if (!observers.Contains(observer))
|
||||||
observers.Add(observer);
|
observers.Add(observer);
|
||||||
|
|
||||||
return new Unsubscriber(observers, observer);
|
return new Unsubscriber<Twit>(observers, observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddTwit(Twit twit)
|
public void AddTwit(Twit twit)
|
||||||
@@ -37,23 +37,6 @@ namespace ObserverPattern.Twits
|
|||||||
{
|
{
|
||||||
observer.OnCompleted();
|
observer.OnCompleted();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class Unsubscriber : IDisposable
|
|
||||||
{
|
|
||||||
private List<IObserver<Twit>> _observers;
|
|
||||||
private IObserver<Twit> _observer;
|
|
||||||
|
|
||||||
public Unsubscriber(List<IObserver<Twit>> observers, IObserver<Twit> observer)
|
|
||||||
{
|
|
||||||
_observers = observers;
|
|
||||||
_observer = observer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (!(_observer == null)) _observers.Remove(_observer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
src/ObserverPattern/Unsubscriber.cs
Normal file
24
src/ObserverPattern/Unsubscriber.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ObserverPattern
|
||||||
|
{
|
||||||
|
public class Unsubscriber<T> : IDisposable
|
||||||
|
{
|
||||||
|
private List<IObserver<T>> _observers;
|
||||||
|
private IObserver<T> _observer;
|
||||||
|
|
||||||
|
public Unsubscriber(List<IObserver<T>> observers, IObserver<T> observer)
|
||||||
|
{
|
||||||
|
_observers = observers;
|
||||||
|
_observer = observer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!(_observer == null)) _observers.Remove(_observer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
"version": "1.0.0-*",
|
"version": "1.0.0-*",
|
||||||
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"NETStandard.Library": "1.6.0"
|
"NETStandard.Library": "1.6.0",
|
||||||
|
"System.Reactive": "3.0.0"
|
||||||
},
|
},
|
||||||
|
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
|
|||||||
Reference in New Issue
Block a user