diff --git a/Program.cs b/Program.cs index e77318e..b01637c 100644 --- a/Program.cs +++ b/Program.cs @@ -18,6 +18,7 @@ using design_patterns.behavioral.chainofresponsability; using design_patterns.behavioral.command; using design_patterns.behavioral.iterator; using design_patterns.behavioral.mediator; +using design_patterns.behavioral.memento; namespace design_patterns { @@ -49,7 +50,8 @@ namespace design_patterns // await ChainOfResponsabilitySample.Run(); // await CommandSample.Run(); // await IteratorSample.Run(); - await MediatorSample.Run(); + // await MediatorSample.Run(); + await MementoSample.Run(); } catch (System.Exception ex) { diff --git a/behavioral/memento/MementoSample.cs b/behavioral/memento/MementoSample.cs new file mode 100644 index 0000000..4172bc5 --- /dev/null +++ b/behavioral/memento/MementoSample.cs @@ -0,0 +1,136 @@ +using System.Globalization; +using System.Text; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace design_patterns.behavioral.memento +{ + /// + /// Memento is a behavioral design pattern that lets you + /// save and restore the previous state of an object + /// without revealing the details of its implementation. + /// + /// Use it when: + /// - you want to produce snapshots of the object’s state + /// to be able to restore a previous state of the object. + /// - direct access to the object’s fields/getters/setters + /// violates its encapsulation. + /// + public class MementoSample + { + public static async Task Run() + { + Console.WriteLine("Behavioral - Memento"); + + var board = new DrawingBoard(); + System.Console.WriteLine(board); + // init state + var memento0 = board.Save(); + + board.DrawLine(new Line(0,0, 10, 20, 1, "red")); + board.DrawLine(new Line(10,5, 15, 25, 2, "green")); + + System.Console.WriteLine(board); + var memento1 = board.Save(); + + board.DrawLine(new Line(20,20, 5, 20, 1, "blue")); + + System.Console.WriteLine(board); + var memento2 = board.Save(); + + board.DrawLine(new Line(7, 7, 7, 7, 3, "new red")); + System.Console.WriteLine(board); + var memento3 = board.Save(); + +#if false + // only memento + System.Console.WriteLine("Restore memento1"); + board.Restore(memento1); + System.Console.WriteLine(board); +#else + // memento with undo() + System.Console.WriteLine("Undo one step"); + board.Undo(); + System.Console.WriteLine(board); + + System.Console.WriteLine("Undo one more step"); + board.Undo(); + System.Console.WriteLine(board); + + System.Console.WriteLine("Undo one more more step"); + board.Undo(); + System.Console.WriteLine(board); + System.Console.WriteLine("Undo one more more more step"); + board.Undo(); + System.Console.WriteLine(board); +#endif + } + } + + /// + /// keeps the snapshot of the system/component + /// + public class Memento { + + public List Lines { get; set; } = new List(); + + public Memento(DrawingBoard board) + { + // copy inner Lines and NOT the list reference + this.Lines.AddRange(board.Lines); + } + } + + public class DrawingBoard { + public List Lines { get; set; } = new List(); + private Stack _history = new Stack(); + + public void DrawLine(Line line) + { + Lines.Add(line); + } + + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"Board contains: {this.Lines.Count} lines ->"); + foreach (var line in Lines) + { + sb.AppendLine($"Line: from {line.fromX}-{line.fromY} to {line.toX}-{line.toY} width {line.width} color {line.color}"); + } + return sb.ToString(); + } + + public Memento Save() + { + var memento = new Memento(this); + _history.Push(memento); + return memento; + } + + public void Restore(Memento memento) + { + if (memento != null && + _history.Contains(memento)) { + while(!_history.Peek().Equals(memento)) { + _history.Pop(); + } + this.Lines = memento.Lines; + } + } + + public void Undo() { + if(_history.Count>1){ + _history.Pop(); + var memento = _history.Peek(); + Restore(memento); + } + } + } + + public record Line(int fromX, int fromY, + int toX, int toY, + int width, string color); +} \ No newline at end of file