Definition
The proxy pattern provides a placeholder for another object in order to control access to it, but not changing the object’s interface.
Proxy | Usage |
---|---|
Remote proxy | Try to access data in remote server or in different project. |
Virtual proxy | Control access to a resource that is expensive to create. |
Protection proxy | Access 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
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;
}