轉(zhuǎn)載自:
http://patmusing.blog.163.com/blog/static/13583496020101410329439/
Proxy also a.k.a. Surrogate
對于復雜的軟件系統(tǒng)常常有一種處理手法,即增加一層間接層,從而使得系統(tǒng)獲得一種更為靈活、滿足特定需求的解決方案。在面向?qū)ο蟮南到y(tǒng)中,有些對象由于某種原因,比如對象創(chuàng)建的開銷很大,或者某些操作需要安全控制,或者需要進程外的訪問等,直接訪問會給使用者或者系統(tǒng)結構帶來很多麻煩。
Proxy設計模式就是在不失去透明操作對象的同時,通過增加一層間接層來管理、控制這些對象特有的復雜性。

圖1
圖2
表示不同的進程
圖1中假定A和B位于不同的進程,典型的情況是A和B位于互聯(lián)網(wǎng)上兩臺不同的機器上,如果A要訪問B三次,那么A就要如上圖調(diào)用B三次。
圖2中增加一個B的代理,該代理和A位于同一個進程內(nèi),當A要調(diào)用B的功能時,A僅需要調(diào)用B的代理即可,然后B的代理和B之間進行通信。另外如果A要3次調(diào)用B的功能,那么A僅需要3此調(diào)用B的代理即可,而B的代理和B之間有可能只需要一次通信就夠了,由此可見,B的代理有一定的緩沖功能。
Provide a surrogate or placeholder for another object to control access to it. (為其他對象提供一種代理以控制對這個對象的訪問) -GoF
Proxy設計模式之靜態(tài)結構UML類圖:

圖3
說明:
Service:
The interface that both the proxy and the real object will implement. (代理和實際對象必須實現(xiàn)的接口)
ServiceProxy:
ServiceProxy implements Service and forwards method calls to the real object (ServiceImplemention) when appropriate.
(ServiceProxy實現(xiàn)了Service接口,并在合適的時候,將請求傳遞給實際對象ServiceImplementation)
ServiceImplementation:
The real, full implementation of the interface. This object will be represented by the Proxy object.
(真正、完整的接口實現(xiàn),該對象由Proxy對象代表)
A proxy (or stub) is a representative for another object. To enable the proxy to represent the real object, the proxy has to implement the exact same interface as the real object. Furthermore, the proxy keeps a reference to the real object. The proxy needs the reference to the real object so that it can call methods on the real object if necessary. The clients will be interacting with the proxy, but the proxy can delegate the execution to the real object. The proxy implements the same interface as the real object, but can perform tasks that the real object does not, such as remote communication or security.
Use the Proxy pattern when you need a more elaborate reference to an object instead of just a regular one:
- Remote proxy: When you need a local representative for an object in another address space(e.g. JVM)
- Virtual proxy: Acts as a placeholder and delays creating expensive objects.
- Protection proxy: Determines access rights to the real object.
Remote Proxy C++模擬代碼:
// Proxy.h
#include <string>
#include <iostream>
#include <string>
using namespace std;
class IEmployee
{
public:
virtual string get_name(int ID) = 0;
virtual int get_age(int ID) = 0;
virtual double get_salary(int ID) = 0;
public:
virtual ~IEmployee();
};
IEmployee::~IEmployee()
{
cout << "in the destructor of IEmployee..." << endl;
}
class Employee : public IEmployee
{
public:
string get_name(int ID);
int get_age(int ID);
double get_salary(int ID);
~Employee();
};
string Employee::get_name(int ID)
{
// ... 假定此處查詢數(shù)據(jù)庫,獲得ID對應員工的姓名
string name = "玄機逸士";
return name;
}
int Employee::get_age(int ID)
{
// ... 假定此處查詢數(shù)據(jù)庫,獲得ID對應員工的年齡
int age = 27;
return age;
}
double Employee::get_salary(int ID)
{
// ... 假定此處查詢數(shù)據(jù)庫,獲得ID對應員工的工資
double salary = 50000.1;
return salary;
}
Employee::~Employee()
{
cout << "in the destructor of Employee..." << endl;
}
class EmployeeProxy : public IEmployee
{
public:
string get_name(int ID);
int get_age(int ID);
double get_salary(int ID);
~EmployeeProxy();
};
string EmployeeProxy::get_name(int ID)
{
// ...假定此處通過socket或者RPC等其他方式訪問Employee中的get_name(int ID)方法,并接受相應的返回值
string name = "玄機逸士";
return name;
}
int EmployeeProxy::get_age(int ID)
{
// ...假定此處通過socket或者RPC等其他方式訪問Employee中的get_age(int ID)方法,并接受相應的返回值
int age = 27;
return age;
}
double EmployeeProxy::get_salary(int ID)
{
// ...假定此處通過socket或者RPC等其他方式訪問Employee中的get_salary(int ID)方法,并接受相應的返回值
double salary = 50000.1;
return salary;
}
EmployeeProxy::~EmployeeProxy()
{
cout << "in the destructor of EmployeeProxy..." << endl;
}
// Proxy.cpp
#include "Proxy.h"
int main(int argc, char **argv)
{
IEmployee *employee = new EmployeeProxy;
cout << employee->get_name(10) << endl;
cout << employee->get_age(10) << endl;
cout << employee->get_salary(10) << endl;
delete employee;
return 0;
}
輸出結果:
玄機逸士
27
50000.1
in the destructor of EmployeeProxy…
in the destructor of IEmployee…
說明:
- IEmployee是接口,相當于圖3中的Service;
- Employee是在遠程地址空間中對接口IEmployee的實現(xiàn);
- EmployeeProxy是在本地地址空間中對IEmployee的實現(xiàn),同時它通過網(wǎng)絡依賴Employee
- main函數(shù)(HRSystem)是客戶程序。它向EmployeeProxy發(fā)出請求,EmployeeProxy得到HRSystem發(fā)出的請求后,通過網(wǎng)絡將請求提交給遠程的Employee,Employee接受請求并做出相關處理,將處理的結果返回給EmployeeProxy,EmployeeProxy將結果返回給HRSystem。
圖4
* 要完整實現(xiàn)一個Remote Proxy需要比較多的代碼,在此就用程序中的部分注釋來代替了。
Virtual Proxy C++示例代碼:
// Proxy.h
#define FILENAME "contacts.cbf"
// 一個簡單的聯(lián)系人類
class Contact
{
private:
string name;
string email;
public:
Contact()
{
}
Contact(string name, string email) : name(name), email(email)
{
}
~Contact()
{
cout << "in the destructor of Contact..." << endl;
}
public:
// 下面幾個成員函數(shù)都是getter
string get_name() const
{
return name;
}
string get_email() const
{
return email;
}
};
// 聯(lián)絡本:一個抽象類,用作接口,它規(guī)定了聯(lián)絡本的相關方法
class IContactBook
{
protected:
public:
virtual void add(const Contact& contact) = 0; // 增加一個聯(lián)系人
virtual vector<Contact> get_contact(const string& name) = 0; // 查詢聯(lián)系人,有可能重名
virtual multimap<string, Contact> get_all_contacts() = 0; // 獲取所有聯(lián)系人
virtual void save() = 0; // 保存數(shù)據(jù)
public:
virtual ~IContactBook()
{
cout << "in the destructor of IContactBook..." << endl;
}
};
// ContactBook繼承IContactBook,該類實現(xiàn)了IContactBook中所有規(guī)定的方法,
// 它是一個“real object”(真實對象),將由ContactBookProxy來代理
class ContactBook : public IContactBook
{
private:
multimap<string, Contact> contacts;
public:
ContactBook()
{
Contact *contact = new Contact;
ifstream file(FILENAME, ios::in|ios::binary); // 打開文件
if(!file)
{
cout << "can not open file..." << endl;
return;
}
Else // 將文件中的數(shù)據(jù)讀入contacts
{
file.seekg (0, ios::end);
int length = file.tellg();
file.seekg (0, ios::beg);
int element_number = length / sizeof(Contact);
cout << "element_number = " << element_number << endl;
for(int i = 0; i < element_number; i++)
{
file.seekg(sizeof(Contact) * i, ios::beg);
file.read((char *)contact, sizeof(Contact));
contacts.insert(pair<string, Contact>(contact->get_name(), *contact));
}
}
file.close();
delete contact;
contact = 0;
}
~ContactBook()
{
//save();
cout << "in the destructor of ContactBook..." << endl;
}
public:
// 根據(jù)名字獲取聯(lián)系人,由于有可能重名,因此返回值是一個vector<Contact>
vector<Contact> get_contact(const string& name)
{
multimap<string, Contact>::iterator it;
pair<multimap<string, Contact>::iterator, multimap<string, Contact>::iterator> ret;
ret = contacts.equal_range(name);
vector<Contact> contact_found;
for(it = ret.first; it != ret.second; it++)
{
contact_found.push_back(it->second);
}
return contact_found;
}
// 增加一個聯(lián)系人
void add(const Contact& contact)
{
string email;
vector<Contact> vcontact = get_contact(contact.get_name());
// 如果multimap contacts中不存在該聯(lián)系人
if(vcontact.empty())
{
// 則將聯(lián)系人contact加入到multimap中,聯(lián)系人contact的name作為key
contacts.insert(pair<string, Contact>(contact.get_name(), contact));
}
else // 同名的聯(lián)系人
{
email = contact.get_email();
int i = 0;
for(vector<Contact>::iterator it = vcontact.begin(); it != vcontact.end(); it++)
{
if(!(email == it->get_email())) // 同名的聯(lián)系人,但email不同。在這里,
{ // 我們假定email是唯一的,實際情況大多如此
i++;
}
}
if(i == vcontact.size()) // 和找出來所有同名的人的email地址都不一樣
{
contacts.insert(pair<string, Contact>(contact.get_name(), contact));
return;
}
}
}
// 將contacts中的所有聯(lián)系人存入到文件中
void save()
{
ofstream file(FILENAME, ios::out|ios::binary);
if(!file)
{
cout << "can not open file..." << endl;
return;
}
for(multimap<string, Contact>::iterator it = contacts.begin(); it != contacts.end(); it++)
{
file.write((const char *)(&(it->second)), sizeof(Contact));
}
file.close();
}
// 獲取所有聯(lián)系人
multimap<string, Contact> get_all_contacts()
{
return contacts;
}
// 一個輔助函數(shù),將被Proxy調(diào)用
void set_contacts(const multimap<string, Contact>& lcontacts)
{
contacts.erase(contacts.begin(), contacts.end());
contacts = lcontacts;
}
};
// 代理
class ContactBookProxy : public IContactBook
{
private:
IContactBook *contact_book; // 存放真實對象
multimap<string, Contact> local_contacts; // 本地聯(lián)系人數(shù)據(jù)
public:
ContactBookProxy()
{
contact_book = new ContactBook; // 創(chuàng)建真實對象
local_contacts = contact_book->get_all_contacts(); // 將真實對象中的數(shù)據(jù)取到本地
delete contact_book; // 取出數(shù)據(jù)后,立即銷毀真實對象
contact_book = 0; // 此后,均指操作本地聯(lián)系人數(shù)據(jù)local_contacts
}
~ContactBookProxy()
{
cout << "in the destructor of ContactBookProxy..." << endl;
if(!contact_book)
{
delete contact_book;
contact_book = 0;
}
}
vector<Contact> get_contact(const string& name)
{
// 只操作本地數(shù)據(jù)local_contacts,因為此時local_contacts已經(jīng)包含了真實對象中的所有數(shù)據(jù)
multimap<string, Contact>::iterator it;
pair<multimap<string, Contact>::iterator, multimap<string, Contact>::iterator> ret;
ret = local_contacts.equal_range(name);
vector<Contact> contact_found;
for(it = ret.first; it != ret.second; it++)
{
contact_found.push_back(it->second);
}
return contact_found;
}
void add(const Contact& contact)
{
string email;
vector<Contact> vcontact = get_contact(contact.get_name());
// 如果multimap contacts中不存在該聯(lián)系人
if(vcontact.empty())
{
// 則將聯(lián)系人contact加入到multimap中,聯(lián)系人contact的name作為key
local_contacts.insert(pair<string, Contact>(contact.get_name(), contact));
}
else // 同名的聯(lián)系人
{
email = contact.get_email();
int i = 0;
for(vector<Contact>::iterator it = vcontact.begin(); it != vcontact.end(); it++)
{
if(!(email == it->get_email())) // 同名的聯(lián)系人,但email不同。在這里,
{ // 我們假定email是唯一的,實際情況大多如此
i++;
}
}
if(i == vcontact.size()) // 和找出來所有同名的人的email地址都不一樣
{
local_contacts.insert(pair<string, Contact>(contact.get_name(), contact));
return;
}
}
}
void save()
{
if(!contact_book)
{
contact_book = new ContactBook;
}
ContactBook *cb = dynamic_cast<ContactBook*>(contact_book); // down casting
cb->set_contacts(local_contacts);
contact_book->save();
}
multimap<string, Contact> get_all_contacts()
{
return local_contacts;
}
};
// Proxy.cpp
int main(int argc, char **argv)
{
IContactBook *contact_proxy = new ContactBookProxy;
contact_proxy->add(Contact("玄機逸士", "xjys@pnft.com"));
contact_proxy->add(Contact("玄機逸士", "xjys@pnft.com"));
contact_proxy->add(Contact("上官天野", "sgty@pnft.com"));
contact_proxy->add(Contact("上官天野", "sgty1@pnft.com"));
contact_proxy->add(Contact("上官天野", "sgty2@pnft.com"));
contact_proxy->add(Contact("黃家四娘", "hjsn@pnft.com"));
contact_proxy->save();
vector<Contact> vec_contact = contact_proxy->get_contact("上官天野");
for(vector<Contact>::const_iterator it = vec_contact.begin(); it != vec_contact.end(); it++)
{
cout << it->get_name() << " : " << it->get_email() << endl;
}
cout << "------------------------------------" << endl;
multimap<string, Contact> map_all_contacts(contact_proxy->get_all_contacts());
for(multimap<string, Contact>::iterator it = map_all_contacts.begin(); it != map_all_contacts.end(); it++)
{
cout << it->first << " : " << (it->second).get_email() << endl;
}
delete contact_proxy;
return 0;
}
輸出結果:
element_number = 5
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of ContactBook...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of IContactBook...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
element_number = 5
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
上官天野 : sgty@pnft.com
上官天野 : sgty1@pnft.com
上官天野 : sgty2@pnft.com
------------------------------------
黃家四娘 : hjsn@pnft.com
上官天野 : sgty@pnft.com
上官天野 : sgty1@pnft.com
上官天野 : sgty2@pnft.com
玄機逸士 : xjys@pnft.com
in the destructor of ContactBookProxy...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of IContactBook...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
in the destructor of Contact...
上述代碼的要點是:首先將真實對象中的數(shù)據(jù)拷貝到代理,并立即銷毀真實對象,然后客戶端程序一直對代理進行操作,直到所需要的操作完成后,將代理中的結果返回給真實對象,并由真實對象保存到文件中。嚴格地說,這個示例代碼并不是真正意義上的Virtual Proxy,因為它并沒有延遲真實對象的創(chuàng)建。不過要實現(xiàn)真正意義上Virtual Proxy也并不困難。
Protection proxy的示例代碼,和前面的代碼差不多,只是在proxy的成員函數(shù)在調(diào)用與之對應的真實對象的成員函數(shù)之前,進行保護性檢查。如果通過了檢查則調(diào)用真實對象的對應成員函數(shù),否則,不調(diào)用并提示相關信息。具體代碼略。