diff --git a/DesignPatternGuru/DesignPatternGuru.sln b/DesignPatternGuru/DesignPatternGuru.sln index 88b71c6..7aae73b 100644 --- a/DesignPatternGuru/DesignPatternGuru.sln +++ b/DesignPatternGuru/DesignPatternGuru.sln @@ -41,6 +41,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Iterator", "Iterator\Iterat EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mediator", "Mediator\Mediator.csproj", "{08D296F6-6698-4FCB-B605-318D9381F975}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Memonto", "Memonto\Memonto.csproj", "{A6E39678-6214-4BD2-B616-A3350340E5AB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -111,6 +113,10 @@ Global {08D296F6-6698-4FCB-B605-318D9381F975}.Debug|Any CPU.Build.0 = Debug|Any CPU {08D296F6-6698-4FCB-B605-318D9381F975}.Release|Any CPU.ActiveCfg = Release|Any CPU {08D296F6-6698-4FCB-B605-318D9381F975}.Release|Any CPU.Build.0 = Release|Any CPU + {A6E39678-6214-4BD2-B616-A3350340E5AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6E39678-6214-4BD2-B616-A3350340E5AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6E39678-6214-4BD2-B616-A3350340E5AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6E39678-6214-4BD2-B616-A3350340E5AB}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -132,6 +138,7 @@ Global {629A51B1-04D9-4636-8E21-1712DCFF21DF} = {E3B8A482-1A9A-4B6E-8310-050A44C8E379} {6619433E-476B-404C-94A0-D0C0FE52DE41} = {E3B8A482-1A9A-4B6E-8310-050A44C8E379} {08D296F6-6698-4FCB-B605-318D9381F975} = {E3B8A482-1A9A-4B6E-8310-050A44C8E379} + {A6E39678-6214-4BD2-B616-A3350340E5AB} = {E3B8A482-1A9A-4B6E-8310-050A44C8E379} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3E5A9C6B-2E8A-466E-B5E0-4379902EFFAC} diff --git a/DesignPatternGuru/Memonto/Mementos/Caretaker.cs b/DesignPatternGuru/Memonto/Mementos/Caretaker.cs new file mode 100644 index 0000000..06981e0 --- /dev/null +++ b/DesignPatternGuru/Memonto/Mementos/Caretaker.cs @@ -0,0 +1,57 @@ +using Memonto.Originators; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Memonto.Mementos +{ + internal class Caretaker + { + private List _mementos = new List(); + + private Originator _originator = null; + + public Caretaker(Originator originator) + { + _originator = originator; + } + + public void Backup() + { + Console.WriteLine(); + Console.WriteLine("Caretaker: Saving originator's state..."); + _mementos.Add(_originator.Save()); + } + + public void Undo() + { + if (_mementos.Count < 1) + return; + + IMemento memento = _mementos.Last(); + _mementos.Remove(memento); + + Console.WriteLine($"Caretaker: Restoring state to: {memento.GetName()}"); + try + { + _originator.Restore(memento); + } + catch (Exception ex) + { + Console.WriteLine($"Undo exception: {ex.Message}"); + Undo(); + } + } + + public void ShowHistory() + { + Console.WriteLine("Caretaker: Here's the list of mementos: "); + foreach (var memento in _mementos) + { + Console.WriteLine(memento.GetName()); + } + } + } +} diff --git a/DesignPatternGuru/Memonto/Mementos/ConcreteMemento.cs b/DesignPatternGuru/Memonto/Mementos/ConcreteMemento.cs new file mode 100644 index 0000000..7f67e5f --- /dev/null +++ b/DesignPatternGuru/Memonto/Mementos/ConcreteMemento.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Memonto.Mementos +{ + internal class ConcreteMemento : IMemento + { + private string _state; + + private DateTime _date; + + public ConcreteMemento(string state) + { + _state = state; + _date = DateTime.Now; + } + + public DateTime GetDate() + { + return _date; + } + + public string GetName() + { + return $"[{_date}] {_state.Substring(0, 9)}..."; + } + + public string GetState() + { + return _state; + } + } +} diff --git a/DesignPatternGuru/Memonto/Mementos/IMemento.cs b/DesignPatternGuru/Memonto/Mementos/IMemento.cs new file mode 100644 index 0000000..fc23390 --- /dev/null +++ b/DesignPatternGuru/Memonto/Mementos/IMemento.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Memonto.Mementos +{ + internal interface IMemento + { + string GetName(); + + string GetState(); + + DateTime GetDate(); + } +} diff --git a/DesignPatternGuru/Memonto/Memonto.csproj b/DesignPatternGuru/Memonto/Memonto.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/DesignPatternGuru/Memonto/Memonto.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/DesignPatternGuru/Memonto/Originators/Originator.cs b/DesignPatternGuru/Memonto/Originators/Originator.cs new file mode 100644 index 0000000..c6710f0 --- /dev/null +++ b/DesignPatternGuru/Memonto/Originators/Originator.cs @@ -0,0 +1,55 @@ +using Memonto.Mementos; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Memonto.Originators +{ + internal class Originator + { + private string _state; + + public Originator(string state) + { + _state = state; + Console.WriteLine($"Originator: My initial state is: {state}"); + } + + public void DoSomething() + { + Console.WriteLine("Originator: I'm doing something important."); + _state = GenerateRandomString(30); + Console.WriteLine($"Originator: And my state has changed to: {_state}"); + } + + private string GenerateRandomString(int length = 10) + { + string allowedSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + string result = string.Empty; + + while (length > 0 ) + { + result += allowedSymbols[new Random().Next(0, allowedSymbols.Length)]; + length--; + } + + return result; + } + + public IMemento Save() + { + return new ConcreteMemento( _state ); + } + + public void Restore(IMemento memento ) + { + if (!(memento is ConcreteMemento)) + throw new Exception("Unknown memento class " + memento.ToString()); + + _state = memento.GetState(); + Console.WriteLine($"Originator: My state has changed to: {_state}"); + } + } +} diff --git a/DesignPatternGuru/Memonto/Program.cs b/DesignPatternGuru/Memonto/Program.cs new file mode 100644 index 0000000..c58a6ec --- /dev/null +++ b/DesignPatternGuru/Memonto/Program.cs @@ -0,0 +1,38 @@ +using Memonto.Mementos; +using Memonto.Originators; + +namespace Memonto +{ + internal class Program + { + static void Main(string[] args) + { + Originator originator = new Originator("Super-duper-super-puper-super."); + Caretaker caretaker = new Caretaker(originator); + + caretaker.Backup(); + originator.DoSomething(); + + caretaker.Backup(); + originator.DoSomething(); + + caretaker.Backup(); + originator.DoSomething(); + + Console.WriteLine(); + caretaker.ShowHistory(); + + Console.WriteLine(); + Console.WriteLine("Client: Now, let's rollback!"); + Console.WriteLine(); + caretaker.Undo(); + + Console.WriteLine(); + Console.WriteLine("Client: Once more!"); + Console.WriteLine(); + caretaker.Undo(); + + Console.WriteLine(); + } + } +} \ No newline at end of file