diff --git a/src/BehavioralPatterns/Program.cs b/src/BehavioralPatterns/Program.cs
index 292b292..feeb977 100644
--- a/src/BehavioralPatterns/Program.cs
+++ b/src/BehavioralPatterns/Program.cs
@@ -38,9 +38,11 @@ namespace BehavioralPatterns
MementoPatternExamples.Run();
+ Console.ReadKey();
ObserverPatternExamples.Run();
Console.ReadKey();
+
}
}
}
diff --git a/src/CommandPattern/CommandPatternExamples.cs b/src/CommandPattern/CommandPatternExamples.cs
index 0e50ac4..d388b0e 100644
--- a/src/CommandPattern/CommandPatternExamples.cs
+++ b/src/CommandPattern/CommandPatternExamples.cs
@@ -31,12 +31,6 @@ namespace CommandPattern
}
- private static void GoToNextStep()
- {
- Console.ReadKey();
- Console.Clear();
- }
-
public static string GetPatternDescription()
{
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:
http://gernotklingler.com/blog/implementing-undoredo-with-the-command-pattern/";
}
+
+ private static void GoToNextStep()
+ {
+ Console.ReadKey();
+ Console.Clear();
+ }
}
}
diff --git a/src/ObserverPattern/ObserverPatternExamples.cs b/src/ObserverPattern/ObserverPatternExamples.cs
index c6c640b..de480a8 100644
--- a/src/ObserverPattern/ObserverPatternExamples.cs
+++ b/src/ObserverPattern/ObserverPatternExamples.cs
@@ -1,4 +1,5 @@
-using ObserverPattern.Twits;
+using ObserverPattern.StockUpdateEvents;
+using ObserverPattern.Twits;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,8 +12,66 @@ namespace ObserverPattern
{
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();
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();
}
}
}
diff --git a/src/ObserverPattern/StockUpdateEvents/AaplObserver.cs b/src/ObserverPattern/StockUpdateEvents/AaplObserver.cs
new file mode 100644
index 0000000..c83592e
--- /dev/null
+++ b/src/ObserverPattern/StockUpdateEvents/AaplObserver.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace ObserverPattern.StockUpdateEvents
+{
+ ///
+ /// Observer
+ ///
+ 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;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ObserverPattern/StockUpdateEvents/LondonStockObserver.cs b/src/ObserverPattern/StockUpdateEvents/LondonStockObserver.cs
new file mode 100644
index 0000000..adfad53
--- /dev/null
+++ b/src/ObserverPattern/StockUpdateEvents/LondonStockObserver.cs
@@ -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;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ObserverPattern/StockUpdateEvents/Stock.cs b/src/ObserverPattern/StockUpdateEvents/Stock.cs
new file mode 100644
index 0000000..5abd83f
--- /dev/null
+++ b/src/ObserverPattern/StockUpdateEvents/Stock.cs
@@ -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; }
+ }
+}
\ No newline at end of file
diff --git a/src/ObserverPattern/StockUpdateEvents/StockSubject.cs b/src/ObserverPattern/StockUpdateEvents/StockSubject.cs
new file mode 100644
index 0000000..db10ba8
--- /dev/null
+++ b/src/ObserverPattern/StockUpdateEvents/StockSubject.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace ObserverPattern.StockUpdateEvents
+{
+ ///
+ /// Subject
+ ///
+ public class StockSubject
+ {
+
+ public void UpdateStockValue(Stock s)
+ {
+ StockUpdated?.Invoke(this, new StockUpdateEventArgs(s));
+ }
+
+ public event EventHandler StockUpdated;
+ }
+}
\ No newline at end of file
diff --git a/src/ObserverPattern/StockUpdateEvents/StockUpdateEventArgs.cs b/src/ObserverPattern/StockUpdateEvents/StockUpdateEventArgs.cs
new file mode 100644
index 0000000..5f4d44b
--- /dev/null
+++ b/src/ObserverPattern/StockUpdateEvents/StockUpdateEventArgs.cs
@@ -0,0 +1,12 @@
+namespace ObserverPattern.StockUpdateEvents
+{
+ public class StockUpdateEventArgs
+ {
+ public Stock Stock { get; set; }
+
+ public StockUpdateEventArgs(Stock stock)
+ {
+ Stock = stock;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ObserverPattern/StockUpdateEvents/StockUpdateEventsExample.cs b/src/ObserverPattern/StockUpdateEvents/StockUpdateEventsExample.cs
new file mode 100644
index 0000000..bb2b740
--- /dev/null
+++ b/src/ObserverPattern/StockUpdateEvents/StockUpdateEventsExample.cs
@@ -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(
+ ev => stockSubject.StockUpdated += ev,
+ ev => stockSubject.StockUpdated -= ev).Where(s => s.EventArgs.Stock.Name == "FTSE");
+
+ var aaplObserver = Observable.FromEventPattern(
+ 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 eventP)
+ {
+ Console.WriteLine("apple updated, new value: {0}", eventP.EventArgs.Stock.Value);
+ }
+
+ private void PrintLondonStockPriceUpdate(EventPattern 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 });
+ }
+ }
+}
diff --git a/src/ObserverPattern/Twits/ObservableTwitsExample.cs b/src/ObserverPattern/Twits/ObservableTwitsExample.cs
index aeff52f..29d4870 100644
--- a/src/ObserverPattern/Twits/ObservableTwitsExample.cs
+++ b/src/ObserverPattern/Twits/ObservableTwitsExample.cs
@@ -11,16 +11,16 @@ namespace ObserverPattern.Twits
{
TwitObservable observable = new TwitObservable();
- TwitUser t100 = new TwitUser("t100", observable);
- TwitUser r2d2 = new TwitUser("R2-D2", observable);
+ using (TwitUser t100 = new TwitUser("t100", 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");
-
- t100.Dispose();
-
- observable.ItsGoingHomeTime();
+ observable.ItsGoingHomeTime();
+ }
+
}
}
}
diff --git a/src/ObserverPattern/Twits/TwitObservable.cs b/src/ObserverPattern/Twits/TwitObservable.cs
index 75a9ff2..c5cc320 100644
--- a/src/ObserverPattern/Twits/TwitObservable.cs
+++ b/src/ObserverPattern/Twits/TwitObservable.cs
@@ -20,7 +20,7 @@ namespace ObserverPattern.Twits
if (!observers.Contains(observer))
observers.Add(observer);
- return new Unsubscriber(observers, observer);
+ return new Unsubscriber(observers, observer);
}
public void AddTwit(Twit twit)
@@ -37,23 +37,6 @@ namespace ObserverPattern.Twits
{
observer.OnCompleted();
}
- }
-
- private class Unsubscriber : IDisposable
- {
- private List> _observers;
- private IObserver _observer;
-
- public Unsubscriber(List> observers, IObserver observer)
- {
- _observers = observers;
- _observer = observer;
- }
-
- public void Dispose()
- {
- if (!(_observer == null)) _observers.Remove(_observer);
- }
}
}
diff --git a/src/ObserverPattern/Unsubscriber.cs b/src/ObserverPattern/Unsubscriber.cs
new file mode 100644
index 0000000..6e16cee
--- /dev/null
+++ b/src/ObserverPattern/Unsubscriber.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace ObserverPattern
+{
+ public class Unsubscriber : IDisposable
+ {
+ private List> _observers;
+ private IObserver _observer;
+
+ public Unsubscriber(List> observers, IObserver observer)
+ {
+ _observers = observers;
+ _observer = observer;
+ }
+
+ public void Dispose()
+ {
+ if (!(_observer == null)) _observers.Remove(_observer);
+ }
+ }
+}
diff --git a/src/ObserverPattern/project.json b/src/ObserverPattern/project.json
index b5b5a5c..9742072 100644
--- a/src/ObserverPattern/project.json
+++ b/src/ObserverPattern/project.json
@@ -2,7 +2,8 @@
"version": "1.0.0-*",
"dependencies": {
- "NETStandard.Library": "1.6.0"
+ "NETStandard.Library": "1.6.0",
+ "System.Reactive": "3.0.0"
},
"frameworks": {