The Proxy design pattern is in charge of managing another class.
It's like a firewall that you cannot overstep.
There are several reasons to use a Proxy instead of directly another class.
For example it can check if a client accessing an object has permission to do that or it can substitute to this object until someone really needs it (in order to avoid useless memory loading).
So it's a more complex object than the real one.
Let's see that in this Proxy design pattern tutorial.
First of all
First thing to note is that the Proxy inherites from the same interface as the real class to handle.
It's exactly the same class except that in the Proxy we'll have more methods to manage the real one.
In our example we're going to simulate a document with pages to display.
On each page there are different elements to display:
- text;
- image;
- video;
- or nothing.
So when we open the document, instead of loading all elements of all pages, we're going to load only elements needed by the current page.
It means that if you open the document on page 1, only the elements on page 1 will be loaded and thus displayed.
The Proxy will then manage this mechanism and call the corresponding methods from the Page class.
Note that the switch statement can be replaced by a query from a database but for our example it will be enough.
Let's code a bit.
Code
Document.cpp
#include <iostream>
#include "Document.h"
#include "PageProxy.h"
// Badprog.com
//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
Document::Document() {
std::cout << __FUNCTION__ << std::endl;
initProxy();
}
//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
Document::~Document() {
std::cout << __FUNCTION__ << std::endl;
}
//-----------------------------------------------------------------------------
// open
//-----------------------------------------------------------------------------
void Document::open(int pageNumber) {
_proxy.displayContent(pageNumber);
}
//-----------------------------------------------------------------------------
// open
//-----------------------------------------------------------------------------
void Document::initProxy() {
}
//-----------------------------------------------------------------------------
// open
//-----------------------------------------------------------------------------
void Document::changeToPage(int pageNumber) {
_proxy.displayContent(pageNumber);
}
Document.h
#ifndef __BADPROG_DOCUMENT_H__
#define __BADPROG_DOCUMENT_H__
#include <memory>
#include "PageProxy.h"
// Badprog.com
class Document
{
public:
// CTOR & DTOR
Document();
~Document();
// other
void open(int page = 1);
void initProxy();
void changeToPage(int pageNumber);
private:
PageProxy _proxy;
};
#endif // __BADPROG_DOCUMENT_H__
IPage.h
#ifndef __BADPROG_IPAGE_H__
#define __BADPROG_IPAGE_H__
// Badprog.com
class IPage
{
public:
virtual ~IPage() {};
virtual void displayText() = 0;
virtual void displayImage() = 0;
virtual void displayVideo() = 0;
virtual void displayEmpty() = 0;
};
#endif // __BADPROG_IPAGE_H__
main.cpp
#include <memory>
#include <iostream>
#include "PageProxy.h"
#include "Document.h"
// Badprog.com
//-----------------------------------------------------------------------------
// main
//-----------------------------------------------------------------------------
int main()
{
Document doc;
doc.open(); // by default it opens page 1
doc.changeToPage(4);
doc.changeToPage(15);
doc.changeToPage(24);
doc.changeToPage(1);
doc.changeToPage(37);
doc.changeToPage(59);
return 0;
}
Page.cpp
#include <iostream>
#include "Page.h"
// Badprog.com
//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
Page::Page() {
std::cout << __FUNCTION__ << std::endl;
}
//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
Page::~Page() {
std::cout << std::endl << __FUNCTION__ << std::endl;
}
//-----------------------------------------------------------------------------
// displayText
//-----------------------------------------------------------------------------
void Page::displayText() {
std::cout << "Displaying text." << std::endl;
}
//-----------------------------------------------------------------------------
// displayImage
//-----------------------------------------------------------------------------
void Page::displayImage() {
std::cout << "Displaying an image." << std::endl;
}
//-----------------------------------------------------------------------------
// displayVideo
//-----------------------------------------------------------------------------
void Page::displayVideo() {
std::cout << "Displaying a video." << std::endl;
}
//-----------------------------------------------------------------------------
// displayVideo
//-----------------------------------------------------------------------------
void Page::displayEmpty() {
std::cout << "Sorry nothing to display." << std::endl;
}
Page.h
#ifndef __BADPROG_PAGE_H__
#define __BADPROG_PAGE_H__
#include "IPage.h"
// Badprog.com
class Page : public IPage
{
public:
// CTOR & DTOR
Page();
~Page();
// override
void displayText() override;
void displayImage() override;
void displayVideo() override;
void displayEmpty() override;
};
#endif // __BADPROG_PAGE_H__
PageProxy.cpp
#include <iostream>
#include "PageProxy.h"
// Badprog.com
//-----------------------------------------------------------------------------
// CTOR
//-----------------------------------------------------------------------------
PageProxy::PageProxy() {
std::cout << __FUNCTION__ << std::endl;
_page = NULL;
}
//-----------------------------------------------------------------------------
// DTOR
//-----------------------------------------------------------------------------
PageProxy::~PageProxy() {
std::cout << __FUNCTION__ << std::endl;
}
//-----------------------------------------------------------------------------
// getPage
//-----------------------------------------------------------------------------
std::shared_ptr<Page> PageProxy::getPage() {
if (NULL == _page) {
_page = std::make_shared<Page>();
}
return _page;
}
//-----------------------------------------------------------------------------
// setCurrentPage
//-----------------------------------------------------------------------------
void PageProxy::setCurrentPage(int currentPage) {
_currentPage = currentPage;
}
//-----------------------------------------------------------------------------
// getCurrentPage
//-----------------------------------------------------------------------------
const int PageProxy::getCurrentPage() const {
return _currentPage;
}
//-----------------------------------------------------------------------------
// displayContent
//-----------------------------------------------------------------------------
void PageProxy::displayContent(int pageNumber) {
setCurrentPage(pageNumber);
std::cout << std::endl << "On page \"" << getCurrentPage() << "\":" << std::endl;
switch (pageNumber)
{
case 1:
getPage()->displayText();
break;
case 24:
getPage()->displayText();
getPage()->displayImage();
break;
case 37:
getPage()->displayText();
getPage()->displayImage();
getPage()->displayVideo();
break;
default:
getPage()->displayEmpty();
break;
}
std::cout << std::endl;
}
//-----------------------------------------------------------------------------
// displayText
//-----------------------------------------------------------------------------
void PageProxy::displayText() {
}
//-----------------------------------------------------------------------------
// displayImage
//-----------------------------------------------------------------------------
void PageProxy::displayImage() {
}
//-----------------------------------------------------------------------------
// displayVideo
//-----------------------------------------------------------------------------
void PageProxy::displayVideo() {
}
//-----------------------------------------------------------------------------
// displayEmpty
//-----------------------------------------------------------------------------
void PageProxy::displayEmpty() {
}
PageProxy.h
#ifndef __BADPROG_PAGEPROXY_H__
#define __BADPROG_PAGEPROXY_H__
#include <memory>
#include "IPage.h"
#include "Page.h"
// Badprog.com
class PageProxy : public IPage
{
public:
// CTOR & DTOR
PageProxy();
~PageProxy();
// override
void displayText() override;
void displayImage() override;
void displayVideo() override;
void displayEmpty() override;
// other
void setCurrentPage(int currentPage);
const int getCurrentPage() const;
std::shared_ptr<Page> getPage();
void displayContent(int pageNumber);
private:
int _currentPage;
std::shared_ptr<Page> _page;
};
#endif // __BADPROG_PAGEPROXY_H__
Compiling, linking and running
g++ *.cpp -o go.exe -std=c++1y ; ./go.exe
Result
PageProxy
Document
On page "1":
Page
Displaying text.
On page "4":
Sorry nothing to display.
On page "15":
Sorry nothing to display.
On page "24":
Displaying text.
Displaying an image.
On page "1":
Displaying text.
On page "37":
Displaying text.
Displaying an image.
Displaying a video.
On page "59":
Sorry nothing to display.
~Document
~PageProxy
~Page
Conclusion
As expected the Proxy calls corresponding Page methods depending on the page number requested in the main.cpp.
The Page instance is created once and reused for the rest of the program.
We could have had a Proxy for each element to display like a TextProxy, a VideoProxy or an ImageProxy but it's another story.
Good job, once again, you got it.
Add new comment