Add compressed employee example

This commit is contained in:
Petrutiu Mihai
2016-07-18 15:45:28 +03:00
parent 7192d9e9ce
commit 83e82e03ab
8 changed files with 343 additions and 2 deletions

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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()));
}
}
}

View 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;
}
}
}

View File

@@ -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());
}
}
}

View 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);
}
}

View File

@@ -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());
} }

View File

@@ -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"
}, },