There is this one particular pain point in the whole implementation of the prototype design pattern
and then there's the fact that you have to implement the object copying yourself.
So basically for every single part of the object graph that you're attempting to replicate you basically
have to have either a copy constructor like we've made here or you have to have a copy assignment operator
or you have to have let's say some sort of explicit clone function which actually replicates the object
entirely.
So if your object has just values storage that's OK but if you have something like a pointer.
Well you're in trouble here and this is where there is no magic bullet.
Unfortunately in some of the other programming languages thanks to the functionality of refl. basically
having Midhat Ada over the types you can actually traverse the entire object graph and serialize it
correctly.
But unfortunately in C++ that's not possible.
So there is an approach which is actually taken by many programming languages and that is the idea of
taking an object.
And if you want to replicate it instead of writing special code for it what you're out is the code for
serialization and deserialization.
Now the reason why it works is because typically when you serialize something you want to store all
the aspects of an object.
And when you realize you want to restore all the aspects of an object so it sounds like a really good
deal and maybe that's something that we might want to try.
Here again there is no magic silver bullet in the sense that we have to write some code for actually
serializing things but hopefully it's not too much code actually it's only a small amount of code so
the problem is once again this pointer.
The fact that when we want to save the object we don't just want to save the pointer value one to save
what the pointer points to.
So let's actually go ahead and use Boost serialization for this demo so I'm going to have a couple of
includes here.
I'm going to include boost serialization and we're going to have just the serialization header but also
we'll have the actual means of serialization.
So here I will use Boost archive and I will use the text inputs and outputs archives for the actual
serialization.
There is also binary and other forms of civilization as well just in case you want to try something
else.
I use text here because while it works as well as any other.
So we have a bunch of these includes I'm going to do using namespace boost here just so that we get
all the imports nicely prepared for us and then what we're going to do is we're going to write code
which will allow us to serialize the contact itself and we can actually make most of this code private.
Because it doesn't really matter because we're giving boost special access.
So even if I make this private like so what I can do is first of all I would say friend class serialization
access.
So this gives boost the access to this particular class.
And then what I can do is I can write some code for actually serializing the data and other two different
ways of doing it.
You can either split the serialization into the saving and loading if you want the logic to be different
or you can just have a single function which kind of takes care of both of these and that's what we're
going to do.
So the way it goes is something like the following You have a template template class archive function
which is called serialise so or Seems like indenting is broken here serialize Seery lies like so.
And here you take the archive reference they are as well as the versions surprisingly enough so boost
allows you to version your code effectively.
So we have this function called serialise and this is where we can actually specify what exactly where
serialising.
So here's the thing we take the archive and we use the ampersand operator to define the parts we serialize
So in this case it's name and it's also address.
And surprisingly enough when we say address we don't have the reference the pointer.
That's one of the benefits of using Boost it actually knows that if this is a pointer then we have to
follow the pointer to actually serialize whatever it is that we're interested in.
So having constructed this serialization code for us what we can now do is we can actually start using
it for saving and loading so as to actually clone the object so we can do a little lambda here.
I'm just going to stick Alamdar which is going to be called clone.
So this is going to be a function which takes a contact and replicates it using Boost serialization.
So we take the contact by reference contact C and here's what we do there's actually two steps so first
of all we serialize the contact to let's say a string because in this case what I'm doing is I'm using
a text archive so I can serialize something to an ordinary string so an output string stream for example
holstering stream o ss for example so what I can do is I can make a text output archive so archive colon
colon text archive and I will code OK and provided the stream so the output string stream then I take
the archive.
And I serialize some object into it.
In this case it's the object C that we got as the argument to the lambda itself.
And that's pretty much it.
I can even get it as a string so I can for example say string as equals Sesto the SDR and I would have
the string representation of the contact being serialized.
Now it's actually interesting to look at.
That's actually outputted.
So I would just output it so we get to see the kind of raw representation of a particular object and
then of course what we can do is we can actually serialize it into a new object so essentially we take
all the serialized data and we kind of decompress it or unwrap it into a full object and for that once
again we're going to take the string representation and we'll have an input string stream.
So I string stream that's code ISIS which is going to take that string representation and what we're
going to do is we're going to use the boost input archive this time so archive archive text are called
Hiei which will take the input string stream and here will do the reverse process so we will take the
archive and we will serialize it into a result.
And in this case the result is a contact.
So we'll call the contact result with these serialise everything into the result and then we return
the result.
So this is how you would typically go ahead and serialize and these you realize the whole thing.
So let's actually try it out.
So what I'm going to do is I'll actually use the factory that we've already made to make a new main
office contact.
So I'm going to say that John equals employee.
Employee factory new main office employee called John with the office number 123 and then I will say
auto Jane he calls clone of John.
So this is how it's going to go and I'm going to run this and hopefully we'll get to see what exactly
is happening here of course.
This one hiccup that I've just realized that when we call the factory we actually get a smart pointer.
So once again you have to actually dereference the pointer to get to the actual object because remember
it's a unique PVR because that's the way that we've actually defined it.
OK so what is the problem here.
The problem right now is that we don't have a default constructor in contact and that's something that
you actually need for serialization.
So we only have at the moment he contact the constructor which takes the name and of the address here
and we need an empty constructor as well.
So if we go in here and just select non-live so we get the empty constructor.
Hopefully this time around.
After so many attempts we actually get somewhere and we'll get to see the output of serialization.
OK so here is the fun part.
As you can see we're getting more problems here.
And the reason why is because serialise is no other member overdress.
So what what this does what is essentially forces you to do is it forces you to ensure that every single
part of the overall object graph in this case even the address also has its own serialization code so
we can take some of this code that we've written here.
I'm just going to copy it like so and we can stick it into address as well obviously the serialization
code is going to be different because we're serializing different fields.
But the structure is more or less the same.
So here we have to record the street address as well as the city.
And then of course there is a suite as well.
Now the realization that knows about all the different data types so whether you feed it a string like
here or on the net or it's really no problem it's going to be totally fine with all of these.
And hopefully now that we we run this we get better results of course.
We also have this issue of no default constructor on the dress so let me just add this one as well without
hopefully destroying any semi-colon so let's put the empty address in here.
And well I hope this is the final attempt in our try to actually serialize and serialize the whole thing
and just replicate it basically OK so here is the actual output of what you get as you serialise the
full contact into a piece of text.
This is buth serialization saving it as essentially a chunk of data you can see some familiar parts
here but apart from that while you know there is serialization colon colon archive in here.
Now what we can also do is we can verify that a copy has in fact been made.
So here I have both John and Jane and I can actually try and print them to the console.
Both of them so we can customize Gene a little bit.
So if I say change the name was Jane I'm going to leave the rest as is and we're going to actually see
out both John as well as Jane so John has to have a asterisk in front because obviously it's a smart
pointer.
But Jane is just a reference.
So put Jane in here.
How this is and let's put another and line in here.
I'm going to control at five this thing just so that we get to see what exactly we're getting and hopefully
we'll get to see the copies being made.
So here is John and here is Jane there are identical.
So this highlights the serialization code that we've implemented specifically the clone lambda function
does in fact do what we claimed it to do namely it symbolizes the object and then the DC realizes it.
So the reason why we're doing serialization is because we can kill two birds with one stone we can both
get serialization functionality which might be useful later on but we also get this cloning functionality
there by getting a sort of automatic implementation of the prototype design pattern.
And of course there was an added benefit in so far as it's impossible to miss out on some of the copying
interfaces because remember if you using copy assignment or if you're using copy construction some of
these operations are automatically generated and if they involve pointers then the pointer is simply
going to be copied whereas what's happening here is if you have for example if you're serializing a
dress but you haven't implemented the serialization code for the dress itself the program isn't going
to compile.
So with serialization you get both serialization and the prototype design pattern and you also get some
coding enforcement for you as well.