C++ - Design pattern - Proxy

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. laugh

 

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.