Home [Design Patterns] Proxy Pattern
Post
Cancel

[Design Patterns] Proxy Pattern

Definition

The proxy pattern provides a placeholder for another object in order to control access to it, but not changing the object’s interface.

ProxyUsage
Remote proxyTry to access data in remote server or in different project.
Virtual proxyControl access to a resource that is expensive to create.
Protection proxyAccess management based on access rights.

Scenario

Sometimes, we need to create an object with heavy computational jobs, like parsing large files or reading from big data. We can do lazy evaluations when we actually need them.

Or when our project wants to access an out-of-process application or data, we need some kind of “promise” or “placeholder” to get them.

Class Diagram

Proxy Pattern Proxy Pattern

Instantiating a ConcreteSubject is a heavy computational job. We want to avoid this unless we need to, which is when Request is called. Proxy follows the same interface (constructor) as ConcreteSubject, so that programs can pass proxy around as if it is a ConcreteSubject. Proxy stores the passed-in parameters for instantiating ConcreteSubject and the actual pointer of the object instantiated. The Proxy’s Request method first checks if the object is initialized, then it in turn calls ConcreteSubject’s Request method.

If it is Request method itself heavy computing, the proxy can cache the computed results. This part can also be changed to control access to some specific objects.

We don’t want to change the interface of that original object; the proxy only intercepts between the client and the original object. Unlike the decorator pattern, we only need one proxy layer and don’t need a chain of proxy.

Used Cases

  • Objects that are hard to create; we do lazy evaluation when we actually need it.

Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// proxy.h
#ifndef __PROXY_H__
#define __PROXY_H__

#include <memory>
#include <string>

class ISubject {
public:
    virtual int Request() = 0;
};

class ConcreteSubject : public ISubject {
private:
    std::string file_name_;

public:
    ConcreteSubject(const std::string& file_name);
    int Request() override;
};

class Proxy : public ISubject {
private:
    std::string file_name_;
    std::unique_ptr<ConcreteSubject> concrete_subject_ptr_;

public:
    Proxy(const std::string& file_name);
    int Request() override;
};

#endif  //__PROXY_H__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "proxy.h"

#include <iostream>

ConcreteSubject::ConcreteSubject(const std::string& file_name) : file_name_(file_name) {
    std::cout << "[ConcreteSubject] file name '" << file_name_ << "', computing heavy jobs ..." << std::endl;
}

int ConcreteSubject::Request() {
    return 1;
}

Proxy::Proxy(const std::string& file_name) : file_name_(file_name) {}

int Proxy::Request() {
    if (!concrete_subject_ptr_) {
        std::cout << "[Proxy] Creating 'ConcreteSubject' ..." << std::endl;
        concrete_subject_ptr_ = std::make_unique<ConcreteSubject>(file_name_);
    }
    return concrete_subject_ptr_->Request();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// main.cpp
#include <iostream>

#include "proxy.h"

int main() {
    std::unique_ptr<ISubject> heavy_job1 = std::make_unique<Proxy>("book");

    std::cout << "---------------------" << std::endl;
    std::cout <<  heavy_job1->Request() << std::endl;
    std::cout << "---------------------" << std::endl;

    return 0;
}

Reference

This post is licensed under CC BY 4.0 by the author.