其實代理模式跟這個差不多,對象A(相當於瀏覽器)不是直接存取對象C(相當Web伺服器),而是通過一個中間對象B(相當於Proxy 伺服器)間接訪問對象C。對象B則可以利用這一有利位置為A提供一個與C完全不同的介面,或做一些C本來不做的事!流程如所示:
A -----> B ------> C
這樣B就是C的代理類,C可被稱作實作類別,A是客戶代碼。
==================
下面是原始碼,一共4個檔案。其中實作類別成員函數為全部寫成內嵌函式。
1. 實作類別檔案implementation.h:
// implementation.h --
// 2006-07-21 14:20
#ifndef IMPLEMENTATION_H_
#define IMPLEMENTATION_H_
class Implementation {
public:
Implementation(int v) { value = v; }
void setValue(int v) { value = v; }
int getValue() const { return value; }
private:
int value;
};
#endif
2. 代理類標頭檔interface.h:
// interface.h -- Interface類是Implementation類的代理類
// 2006-07-21 14:23
#ifndef INTERFACE_H_
#define INTERFACE_H_
class Implementation; // forward class declaration
class Interface { // Interface代理類
public:
Interface(int v);
void setValue(int v);
int getValue() const;
~Interface();
private:
Implementation * ptr;
};
#endif
3. 代理類實現檔案interface.cpp:
// interface.cpp
// 2006-07-21 14:25
#include "implementation.h"
#include "interface.h"
Interface::Interface(int v) : ptr(new Implementation(v)) {
}
void Interface::setValue(int v) {
ptr->setValue(v);
}
int Interface::getValue() const {
return ptr->getValue();
}
Interface::~Interface() {
delete ptr;
}
4. 客戶代碼,這裡只是一個主函數,使用代理模式,檔案:useproxy.cpp:
// useproxy.cpp -- Use proxy class
// 2006-07-21 14:29
#include <iostream>
#include "implementation.h"
#include "interface.h"
using namespace std;
int main() {
Interface i(5);
cout << "Interface contains: " << i.getValue() << " before setValue/n";
i.setValue(10);
cout << "Interface contains: " << i.getValue() << " after setValue/n";
return 0;
}
=======================
運行結果:
Interface contains: 5 before setValue
Interface contains: 10 after setValue
Press any key to continue
=========================
說明:在useproxy.cpp檔案中,只有一個Interface類對象,即代理類對象,所有的操作都是調用代理類的公有函數,間接操作實作類別。
---------------------------------------
// 代理類 Demo// 將繼承和容器共用,迫使我們要處理兩個問題:// 控制記憶體配置和把不同類型的對象放入同一個容器中。// 代理類的每個對象都代表另一個對象,該對象可以是// 位於一個完整繼承層次中的任何類的對象。通過在容器中// 用代理對象而不是對象本身來解決以上兩個問題#include <process.h> // system()#include <iostream>using namespace std;// 所有交通工具的基類class Vehicle{public: virtual void start() = 0; // 動態複製 virtual Vehicle* copy() const = 0; // 虛解構函式 virtual ~Vehicle() {}};// 交通工具的代理類class VehicleSurrogate{public: // 無參建構函式,用於建立數組 VehicleSurrogate(); // 用Vehicle 及其衍生類別構造 VehicleSurrogate(const Vehicle&); ~VehicleSurrogate(); // 拷貝及賦值 VehicleSurrogate(const VehicleSurrogate&); VehicleSurrogate& operator=(const VehicleSurrogate&); // Vehicle 的方法 void start();private: Vehicle* p;};VehicleSurrogate::VehicleSurrogate() : p(0) {}VehicleSurrogate::VehicleSurrogate(const Vehicle& v) : p(v.copy()) {}VehicleSurrogate::VehicleSurrogate(const VehicleSurrogate& vs) : p(vs.p ? vs.p->copy() : 0) {}VehicleSurrogate & VehicleSurrogate::operator =(const VehicleSurrogate& vs){ if (p != vs.p) { delete p; p = vs.p ? vs.p->copy() : 0; } return *this;}VehicleSurrogate::~VehicleSurrogate() { delete p; }void VehicleSurrogate::start(){ if (p) p->start(); else cout << "Error" << endl;}class RoadVehicle : public Vehicle{public : void start() { cout << "RoadVehicle start." << endl; } Vehicle* copy() const { return (Vehicle*) new RoadVehicle(*this); } ~RoadVehicle() { }};class AutoVehicle : public RoadVehicle{public : void start() { cout << "AutoVehicle start." << endl; } Vehicle* copy() const { return (Vehicle*) new AutoVehicle(*this); } ~AutoVehicle() { }};void main(){ VehicleSurrogate pa[3]; RoadVehicle* prv = new RoadVehicle(); pa[0] = *prv; delete prv; pa[1] = AutoVehicle(); pa[2] = RoadVehicle(); pa[0].start(); pa[1].start(); pa[2].start(); system("pause");}
---------------------------------
問題:怎樣設計一個c++容器,使它有能力包含類型不同而彼此相關的對象?
假設有一個表示不同種類的交通工具的類派生層次:
class Vehicle
{
public:
virtual double weight() const = 0;
virtual void start() = 0;
//.....
};
class RoadVehicle:public Vehicle {/*...*/};
class AutoVehicle:public RoadVehicle{/*....*/};
為了表述簡單,使用數組來實現。由淺入深的提出以下幾個方案:
方案一: 數組直接儲存物件
Vehicle parking_lot[1000];
AutoVehicle x = /*.....*/
parking_lot[num_vehicles++] = x;
這裡出現兩個問題:
(1) Vehicle 為抽象基類,類Vehicle本身不會有對象,因此定義對象數組也就不可行了。
(2) 即使去掉類Vehicle中的純虛函數,parking_lot 儲存的是衍生類別裁剪後的對象,而不是所有繼承自Vehicle類的對象的集合。
方案二:數組儲存指標
Vehicle* parking_lot[1000];
AutoVehicle x = /*...*/;
parking_lot[num_vehicles++] = &x;
這裡出現下面的問題:
我們儲存在parking_lot中的是指向x的指標,如果x是個局部變數,一但變數x沒有了,parking_lot就不知道指向什麼東西了。我們可以改進一下,放入parking_lot中的值,不是指向原對象的指標,而是指向它們的副本的指標。在釋放數組的時候,也釋放其中所指向的全部對象。上面的代碼可以改寫為:
AutoVehicle x = /*...*/;
parking_lot[num_vehicles++] = AutoVehicle(x);
但是這樣改也帶來了動態記憶體管理的負擔。另外,只有當我們知道要放到parking_lot中的對象的靜態類型後,這種方法才能起作用。為瞭解決這個問題可以使用用虛複製函數, c++中處理未知類型的對象的方法就是使用虛函數。我們可以在類Vehicle中添加純虛函數: virtual Vehicle* copy() const = 0; 則在衍生類別AutoVehicle 中 copy() 函數可以如下實現:
Vehicle* AutoVehicle::copy() const
{
return new AutoVehicle(*this);
}
然後就可以這樣儲存了: parking_lot[num_vehicles++] = x->copy(); 這裡可以在運行時確定所要調用的copy函數。
方案三:定義代理類
方案二已經能較好的解決問題了,但是我們想避免顯示的處理記憶體配置,又能保持類Vehicle在運行時綁定。這裡採用代理類技術,就是定義一個行為和Vehicle對象相似,而又潛在地表示所有繼承自Vehicle類的對象的東西。每個Vehicle代理都代表某個繼承自Vehicle類的對象。只要該代理關聯著這個對象,該對象就肯定存在。簡單的實現了一下代理類,代碼如下:
#include <iostream>
using namespace std;
class Vehicle
{
public:
virtual double weight() const = 0;
virtual Vehicle* copy() = 0;
virtual ~Vehicle() {}
};
class AutoVehicle:public Vehicle
{
public:
double weight() const
{
cout << "AutoVehicle weight" << endl;
return 1;
}
Vehicle* copy()
{
return new AutoVehicle(*this);
}
};
class RoadVehicle:public Vehicle
{
public:
double weight() const
{
cout << "RoadVehicle weight" << endl;
return 2;
}
Vehicle* copy()
{
return new RoadVehicle(*this);
}
};
class VehicleSurrogate
{
public:
VehicleSurrogate();
VehicleSurrogate(Vehicle&);
~VehicleSurrogate();
VehicleSurrogate(const VehicleSurrogate&);
VehicleSurrogate& operator=(const VehicleSurrogate&);
double weight() const;
private:
Vehicle *vp;
};
VehicleSurrogate::VehicleSurrogate():vp(0){} //空代理
VehicleSurrogate::VehicleSurrogate(Vehicle &v):vp(v.copy()){}
VehicleSurrogate::~VehicleSurrogate()
{
delete vp;
}
VehicleSurrogate::VehicleSurrogate(const VehicleSurrogate &v):
vp(v.vp ? v.vp->copy() : 0){}
VehicleSurrogate& VehicleSurrogate::operator=(const VehicleSurrogate &v)
{
if(this != &v)
{
delete vp;
vp = (v.vp ? v.vp->copy() : 0);
}
return *this;
}
double VehicleSurrogate::weight() const
{
if(vp == 0)
{
cout << "empty VehicleSurrogate" << endl;
}
else
{
return vp->weight();
}
}
int main()
{
VehicleSurrogate parking_lot[1000];
AutoVehicle x;
int num_vehicles = 0;
parking_lot[num_vehicles++] = x;
parking_lot[0].weight();
RoadVehicle y;
parking_lot[num_vehicles++] = VehicleSurrogate(y);
parking_lot[1].weight();
return 0;
}
個人感覺代理類最主要的好處就是隱藏的記憶體的分配,方案二中copy就已經可以實現了,只不過看起來不是那麼順眼。代理類用類來表示概念,通過在容器中代理對象而不是對象本身,解決了我們的問題。