Handle - Body Design pattern and it's uses
Introduction
This article talks about Handle-Body pattern and it's uses.
Background
Though, C++ provides private and public access specifiers to differntiate implementation and interface parts of a class, down the line any changes to the private data or member functions implementation would lead to re-compile the whole class.
So instead, it is useful to put interface (public section of a class) and implemntation (private section of a class) details in a 2 seperate classes named as "Handle" and "Body" respectively. And provide a pointer of "Body" class to the "Handle" class. Then make "Handle" forwarding function calss to "Body".
Then provide only the interface class to clients.
Uses:
Here any changes to the implmentation class can be made safely without disturbing or re-compiliing the interface class and thus reducing the compilation time.
Also here the implementation becomes more hidden to the clients and thus achiving more encapsulation.
Future maintainace will also be much easier (if you decide to add or remove any data in the implementation details, will not affect the client's code)
Since the data here is kept seprately with the implemetation class, this pattern is well suited to provide reference-counting facility and thus reliveing developers with the task of memory management as well.
Here is a sample code of Handle and Body class.
The code
Code: Cpp
// ********* body.h - Declares Body class ***********
#include <iostream.h>
class Body { public: // Body features: int get_value () const; void set_value (int val);
// standard construction and destruction: Body (); Body (const Body&); Body& operator = (const Body&); ~Body (); //void swap (Body&);
private: int myVal; };
// ********* End of body.h file **********
// ********* body.cc - Implementation details of "Body" class *********
#include "body.h"
Body::Body() { cout<<"Body::default constructor = \n"; }
Body::Body (const Body& rhs) { cout<<"Body::copy constructor = \n"; myVal = rhs.myVal; }
Body& Body::operator = (const Body &rhs) { cout<<"Body::operator = \n"; if(this != &rhs) { myVal = rhs.myVal; return (*this); } }
Body::~Body() { cout<<"Body::Destructor\n"; }
int Body::get_value() const { cout<<"Body::getValue- myValue = "<<myVal<<"\n"; return (myVal); }
void Body::set_value(int val) { myVal = val; cout<<"Body::set_value-myValue = "<<myVal<<"\n"; }
// ******** End of body.cc file **********
// ******** handle.h - Declares Handle class *********
class Body; // no #include, but forward declaration class Handle { public: // Handle features: int get_value () const; void set_value (int val);
// standard construction and destruction: Handle(); Handle(const Handle&); Handle& operator = (const Handle&); void swap (Handle&); ~Handle ();
private: Body * rep_; // pointer to "Body" class };
// ******** End of handle.h file ************
// ********* handle.cc - Implementation details of Handle class ***********
#include "handle.h" // get the interface #include "body.h" // get the implementation
Handle::Handle () { cout<<"Handle::default constructor = \n"; rep_= new Body; } Handle::Handle (const Handle& rhs) : rep_(0) { cout<<"Handle::copy constructor = \n"; rep_= new Body (*rhs.rep_); } Handle& Handle::operator = (const Handle &rhs) { cout<<"Handle::operator = \n"; if (this != &rhs) { *(rep_) = *(rhs.rep_); return (*this); } } void Handle::swap (Handle& rhs) { Body * tmp = rhs.rep_; rhs.rep_= rep_; rep_= tmp; } Handle::~Handle () { cout<<"Handle::Destructor\n"; delete rep_; rep_= 0; }
int Handle::get_value () const { cout<<"Handle::getValue- myValue\n"; return rep_->get_value (); } void Handle::set_value (int val) { rep_->set_value (val); cout<<"Handle::set_value-myValue\n"; }
// Here is client code, that uses Handle class int main() { Handle h; h.set_value(10); h.get_value();
return(0); }
// *********** End of handle.cc file *************
|