Hello again!
In this video, we are going to look at the Handle-Body pattern. When we are writing object-oriented programs,
one of the things we should do is to have a clear separation between the interface to a class and its
implementation details.
So ideally we have something like this.
We have our class with its interface and implementation, and we have some code which interacts with
an object of this class.
The code should only interact with the interface to the class.
So, by calling the public member functions. And the actual inner details of the class - the way that
the functions are implemented, the data members of the class, and so on - should be completely hidden from
the client.
So the interface acts as a kind of firewall, if you like, between the class implementation and code
that uses the class.
The advantage of this is that if we change something in here, the inner details of the class, then
this does not affect the clients.
So we do not need to modify the code in the client.
The only time we need to modify the client is if the interface changes.
In C++,
we do this by putting the class definition in a header and the implementation of the member functions
in a source file.
We use the access specifiers - public, private or protected - to control access to the implementation.
But this is not 100% proof.
There are still some implementation details which are visible to the client.
The client code can see the names of private data members.
It can see prototypes of member functions which are private or protected.
And if we have any member functions which are inline - template member functions, for example - it
can see those definitions as well.
Because of the way that C++ programs are compiled and built,
all client code which uses this class, must include the header.
And, if there are any changes to this header, even if they are completely irrelevant to the client,
then the client code has to be recompiled.
And for large projects, this can be a big problem.
For example, windows.exe, I believe, takes many hours, or even days, to compile.
If you are making some changes to Windows and you want to compile your changes and try them out,
then you really do not want to compile any more code than is absolutely necessary.
The Handle-Body pattern was introduced to address this.
What we do is, in effect, we split the class into two parts.
So we have two new classes, one for the interface and one for the implementation.
So we have something like this.
We have a Handle class which has the interface.
So that is just the public member functions from the class.
And then we have the Body, which has the actual implementation.
So that will be the original class definition.
When we have a client that wants to interact with this class, it will create a Handle object, and
the Handle constructor will create a Body object, and then the object will manage that Body.
When the client calls a public member function in the Handle, the Handle will forward that call
to the same public member function in the Body.
If you know about the Adaptor design pattern, then this is something similar.
The Handle is making the Body appear to be something else to the client.
In this case, the Handle is making the Body appear as though it is not there.
So as far as the client is concerned, the Body is really a ghost.
If you are writing this class, you would have a header for the Handle, which just defines the Handle
class, with the public member functions only. The Body header defines the Body class, so that would have
the full class definition.
Then when you write the client code, this will include the Handle header, which gives them the public
media functions, but not the Body.
If there are any changes to the implementation details, these will only affect Body.h.
Clients do not include Body.h.
So that means that the clients do not need to be recompiled.
The build process will look something like this.
So we have our Body code, which is in its own little world.
We have the client, which includes the Handle, but not the Body.
So we can do what we like with the Body code, and the client will not need to be compiled.
When we compile and link the program, that will introduce the binary code for the Body into the program binary.
So the client code will be able to call the functions from the binary object.
This is so-called "static" linking, in which all the binary code is combined into a single binary
executable.
There is actually something called "dynamic" linking, which allows us to take this one step further. In
dynamic linking.
We compile the Body code into its own shared library.
So that's a shared object in UNIX terms, a DLL in Windows terms.
And then, when the program runs, the program binary will load up the code from this library.
So that makes the code from the Body available to the client, at run time.
If you are a company which is selling products and you have an update, but you have only changed the code
in the Body - the implementation of this class - then you can just send your customers a new version
of the DLL.
You do not need to have to deliver a new version of the binary, and get your customers to reinstall it.
Okay, so that is it for this video.
We will have some examples in the next video, but until then, keep coding!