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.EmployeeSerialized;
|
||||||
using MememntoPattern.IterativeEmployee;
|
using MememntoPattern.IterativeEmployee;
|
||||||
using System;
|
using System;
|
||||||
@@ -19,20 +20,27 @@ namespace MememntoPattern
|
|||||||
|
|
||||||
GoToNextStep();
|
GoToNextStep();
|
||||||
|
|
||||||
|
//Basic example
|
||||||
EmployeeExample empExample = new EmployeeExample();
|
EmployeeExample empExample = new EmployeeExample();
|
||||||
empExample.Run();
|
empExample.Run();
|
||||||
|
|
||||||
GoToNextStep();
|
GoToNextStep();
|
||||||
|
|
||||||
|
//Limited stack with serialization
|
||||||
EmployeeSerializedExample empSerExample = new EmployeeSerializedExample();
|
EmployeeSerializedExample empSerExample = new EmployeeSerializedExample();
|
||||||
empSerExample.Run();
|
empSerExample.Run();
|
||||||
|
|
||||||
GoToNextStep();
|
GoToNextStep();
|
||||||
|
|
||||||
|
//Iterative memento
|
||||||
EmployeeIterativeExample empIterEx = new EmployeeIterativeExample();
|
EmployeeIterativeExample empIterEx = new EmployeeIterativeExample();
|
||||||
empIterEx.Run();
|
empIterEx.Run();
|
||||||
GoToNextStep();
|
GoToNextStep();
|
||||||
|
|
||||||
|
//Basic memento with compression
|
||||||
|
EmployeeCompressedExample empComp = new EmployeeCompressedExample();
|
||||||
|
empComp.Run();
|
||||||
|
|
||||||
Console.WriteLine(GetPitfalls());
|
Console.WriteLine(GetPitfalls());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"NETStandard.Library": "1.6.0",
|
"NETStandard.Library": "1.6.0",
|
||||||
"Newtonsoft.Json": "9.0.1",
|
"Newtonsoft.Json": "9.0.1",
|
||||||
|
"protobuf-net": "2.1.0",
|
||||||
"System.Runtime.Serialization.Primitives": "4.1.1"
|
"System.Runtime.Serialization.Primitives": "4.1.1"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user