Add compressed employee example
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
using ProtoBuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MememntoPattern.CompressedEmployee
|
||||
{
|
||||
public static class ByteArrayCompressionUtility
|
||||
{
|
||||
public static byte[] Compress(byte[] inputData)
|
||||
{
|
||||
if (inputData == null)
|
||||
throw new ArgumentNullException("inputData must be non-null");
|
||||
|
||||
using (var compressIntoMs = new MemoryStream())
|
||||
{
|
||||
using (var gzs = new BufferedStream(new GZipStream(compressIntoMs, CompressionMode.Compress)))
|
||||
{
|
||||
gzs.Write(inputData, 0, inputData.Length);
|
||||
}
|
||||
return compressIntoMs.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] Decompress(byte[] inputData)
|
||||
{
|
||||
if (inputData == null)
|
||||
throw new ArgumentNullException("inputData must be non-null");
|
||||
|
||||
using (var compressedMs = new MemoryStream(inputData))
|
||||
{
|
||||
using (var decompressedMs = new MemoryStream())
|
||||
{
|
||||
using (var gzs = new BufferedStream(new GZipStream(compressedMs, CompressionMode.Decompress)))
|
||||
{
|
||||
gzs.CopyTo(decompressedMs);
|
||||
}
|
||||
return decompressedMs.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void SerializeAndCompress(this object obj, string fileWhereToSave)
|
||||
{
|
||||
using (FileStream ms = new FileStream(fileWhereToSave, FileMode.Truncate))
|
||||
using (GZipStream zs = new GZipStream(ms, CompressionMode.Compress, true))
|
||||
{
|
||||
Serializer.Serialize(zs, obj);
|
||||
}
|
||||
}
|
||||
|
||||
public static T DecompressAndDeserialize<T>(this string fileToRead)
|
||||
{
|
||||
using (FileStream ms = new FileStream(fileToRead, FileMode.Open))
|
||||
using (GZipStream zs = new GZipStream(ms, CompressionMode.Decompress, true))
|
||||
{
|
||||
return Serializer.Deserialize<T>(zs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using ProtoBuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MememntoPattern.CompressedEmployee
|
||||
{
|
||||
/// <summary>
|
||||
/// Caretaker
|
||||
/// </summary>
|
||||
public class CaretakerListCompressed : ICaretaker<Employee>
|
||||
{
|
||||
private static string fileWhereToSave = Path.GetTempFileName();
|
||||
|
||||
|
||||
public void Revert(Employee obj)
|
||||
{
|
||||
List<byte[]> historyDeserialized = ReadFile();
|
||||
|
||||
if (!historyDeserialized.Any())
|
||||
return;
|
||||
|
||||
var lastItem = historyDeserialized.Pop();
|
||||
|
||||
historyDeserialized.SerializeAndCompress(fileWhereToSave);
|
||||
|
||||
obj.Revert(lastItem);
|
||||
}
|
||||
|
||||
public void Save(Employee obj)
|
||||
{
|
||||
List<byte[]> mementosHistory = ReadFile();
|
||||
mementosHistory.Add(obj.Save());
|
||||
|
||||
mementosHistory.SerializeAndCompress(fileWhereToSave);
|
||||
}
|
||||
|
||||
private static List<byte[]> ReadFile()
|
||||
{
|
||||
List<byte[]> historyDeserialized;
|
||||
|
||||
if (new FileInfo(fileWhereToSave).Length != 0)
|
||||
historyDeserialized = fileWhereToSave.DecompressAndDeserialize<List<byte[]>>();
|
||||
else
|
||||
historyDeserialized = new List<byte[]>();
|
||||
|
||||
return historyDeserialized;
|
||||
}
|
||||
|
||||
public void PrintSizeOfFile()
|
||||
{
|
||||
Console.WriteLine("Size of compressed file: " + SizeSuffix(new FileInfo(fileWhereToSave).Length));
|
||||
}
|
||||
|
||||
public void PrintSizeOfDecompressedHistory()
|
||||
{
|
||||
long historySize = 0;
|
||||
var historyDeserialized = fileWhereToSave.DecompressAndDeserialize<List<byte[]>>();
|
||||
historySize = historyDeserialized.Sum(h => h.Length);
|
||||
|
||||
Console.WriteLine("Size of all the objects saved in caretaker: " + SizeSuffix(historySize));
|
||||
}
|
||||
|
||||
static readonly string[] SizeSuffixes =
|
||||
{ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
|
||||
static string SizeSuffix(Int64 value)
|
||||
{
|
||||
if (value < 0) { return "-" + SizeSuffix(-value); }
|
||||
if (value == 0) { return "0.0 bytes"; }
|
||||
|
||||
int mag = (int)Math.Log(value, 1024);
|
||||
decimal adjustedSize = (decimal)value / (1L << (mag * 10));
|
||||
|
||||
return string.Format("{0:n1} {1}", adjustedSize, SizeSuffixes[mag]);
|
||||
}
|
||||
}
|
||||
|
||||
static class ListExtension
|
||||
{
|
||||
public static T Pop<T>(this List<T> list)
|
||||
{
|
||||
int index = list.Count - 1;
|
||||
T r = list[index];
|
||||
list.RemoveAt(index);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace MememntoPattern.CompressedEmployee
|
||||
{
|
||||
/// <summary>
|
||||
/// Caretaker
|
||||
/// </summary>
|
||||
public class CaretakerObjectCompressed : ICaretaker<Employee>
|
||||
{
|
||||
private Stack<byte[]> employeeHistory;
|
||||
|
||||
public CaretakerObjectCompressed()
|
||||
{
|
||||
employeeHistory = new Stack<byte[]>();
|
||||
}
|
||||
|
||||
public void Save(Employee emp)
|
||||
{
|
||||
employeeHistory.Push(ByteArrayCompressionUtility.Compress(emp.Save()));
|
||||
}
|
||||
|
||||
public void Revert(Employee emp)
|
||||
{
|
||||
if (employeeHistory.Count > 0)
|
||||
emp.Revert(ByteArrayCompressionUtility.Decompress(employeeHistory.Pop()));
|
||||
}
|
||||
}
|
||||
}
|
||||
46
src/MememntoPattern/CompressedEmployee/Employee.cs
Normal file
46
src/MememntoPattern/CompressedEmployee/Employee.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using ProtoBuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MememntoPattern.CompressedEmployee
|
||||
{
|
||||
/// <summary>
|
||||
/// Originator
|
||||
/// </summary>
|
||||
[ProtoContract]
|
||||
public class Employee
|
||||
{
|
||||
[ProtoMember(1)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[ProtoMember(2)]
|
||||
public string Address { get; set; }
|
||||
|
||||
public List<String> Phones { get; set; }
|
||||
|
||||
public byte[] Save()
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
Serializer.Serialize(ms, this);
|
||||
return ms.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void Revert(byte[] memento)
|
||||
{
|
||||
Employee employee;
|
||||
using (MemoryStream ms = new MemoryStream(memento))
|
||||
{
|
||||
employee = Serializer.Deserialize<Employee>(ms);
|
||||
}
|
||||
|
||||
Name = employee.Name;
|
||||
Address = employee.Address;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MememntoPattern.CompressedEmployee
|
||||
{
|
||||
public class EmployeeCompressedExample
|
||||
{
|
||||
public void Run()
|
||||
{
|
||||
CaretakerObjectCompressed caretaker = new CaretakerObjectCompressed();
|
||||
CaretakerListCompressed caretaker2 = new CaretakerListCompressed();
|
||||
Employee e = new Employee();
|
||||
e.Name = "Ghiuri";
|
||||
e.Address = "Stairway to heaven";
|
||||
|
||||
Console.WriteLine("First saved address: {0}", e.Address);
|
||||
caretaker.Save(e);
|
||||
caretaker2.Save(e);
|
||||
|
||||
e.Address = "Highway to hell";
|
||||
|
||||
Console.WriteLine("Second saved address: {0}", e.Address);
|
||||
|
||||
caretaker.Save(e);
|
||||
caretaker2.Save(e);
|
||||
|
||||
e.Address = "Home of the brave";
|
||||
|
||||
Console.WriteLine("Third saved address: {0}", e.Address);
|
||||
|
||||
caretaker.Save(e);
|
||||
caretaker2.Save(e);
|
||||
|
||||
e.Address = "Somesing";
|
||||
|
||||
Console.WriteLine("Address before revert: {0}", e.Address);
|
||||
|
||||
caretaker.Revert(e);
|
||||
caretaker2.Revert(e);
|
||||
|
||||
Console.WriteLine("First reverted Address: {0}", e.Address);
|
||||
|
||||
caretaker.Revert(e);
|
||||
caretaker2.Revert(e);
|
||||
|
||||
Console.WriteLine("Second reverted Address: {0}", e.Address);
|
||||
|
||||
caretaker.Revert(e);
|
||||
caretaker2.Revert(e);
|
||||
|
||||
Console.WriteLine("Third reverted Address: {0}", e.Address);
|
||||
|
||||
caretaker.Revert(e);
|
||||
caretaker2.Revert(e);
|
||||
|
||||
Console.WriteLine("Forth reverted Address: {0}", e.Address);
|
||||
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
e.Address = e.Address + " Le ciupi";
|
||||
|
||||
caretaker2.Save(e);
|
||||
}
|
||||
sw.Stop();
|
||||
Console.WriteLine("It took {0} to save 500 versions of the employee object", sw.Elapsed.ToString());
|
||||
|
||||
caretaker2.PrintSizeOfFile();
|
||||
caretaker2.PrintSizeOfDecompressedHistory();
|
||||
|
||||
sw = Stopwatch.StartNew();
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
caretaker2.Revert(e);
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
Console.WriteLine("It took {0} to revert 500 versions of the employee object", sw.Elapsed.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
14
src/MememntoPattern/CompressedEmployee/ICaretaker.cs
Normal file
14
src/MememntoPattern/CompressedEmployee/ICaretaker.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MememntoPattern.CompressedEmployee
|
||||
{
|
||||
public interface ICaretaker<T>
|
||||
{
|
||||
void Save(T obj);
|
||||
|
||||
void Revert(T obj);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using MememntoPattern.Employee;
|
||||
using MememntoPattern.CompressedEmployee;
|
||||
using MememntoPattern.Employee;
|
||||
using MememntoPattern.EmployeeSerialized;
|
||||
using MememntoPattern.IterativeEmployee;
|
||||
using System;
|
||||
@@ -19,20 +20,27 @@ namespace MememntoPattern
|
||||
|
||||
GoToNextStep();
|
||||
|
||||
//Basic example
|
||||
EmployeeExample empExample = new EmployeeExample();
|
||||
empExample.Run();
|
||||
|
||||
GoToNextStep();
|
||||
|
||||
//Limited stack with serialization
|
||||
EmployeeSerializedExample empSerExample = new EmployeeSerializedExample();
|
||||
empSerExample.Run();
|
||||
|
||||
GoToNextStep();
|
||||
|
||||
|
||||
//Iterative memento
|
||||
EmployeeIterativeExample empIterEx = new EmployeeIterativeExample();
|
||||
empIterEx.Run();
|
||||
GoToNextStep();
|
||||
|
||||
//Basic memento with compression
|
||||
EmployeeCompressedExample empComp = new EmployeeCompressedExample();
|
||||
empComp.Run();
|
||||
|
||||
Console.WriteLine(GetPitfalls());
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.6.0",
|
||||
"Newtonsoft.Json": "9.0.1",
|
||||
"protobuf-net": "2.1.0",
|
||||
"System.Runtime.Serialization.Primitives": "4.1.1"
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user