上篇文章,介紹了《大話設(shè)計(jì)模式》的第6章——裝飾模式。
本篇,來介紹《大話設(shè)計(jì)模式》的第7章——代理模式。并通過C++代碼實(shí)現(xiàn)實(shí)例代碼的功能。
1 代理模式
代理模式的通俗理解為,一個(gè)人(代理人)替另一個(gè) (被代理人)來做某些事情。
代理模式(Proxy):為其它對象提供一種代理以控制對這個(gè)對象的訪問。
代理模式的類圖如下:
-
- Subject:抽象主題類,
定義了需要代理的接口
-
- RealSubject:具體主題類,即被代理類,
實(shí)現(xiàn)具體的接口功能
-
- Proxy:代理類,提供代理接口,其具體的功能實(shí)現(xiàn)是調(diào)用被代理人的接口功能,即
作為中間人來替別人和第三方進(jìn)行交互
2 實(shí)例
背景:書中小故事,卓賈易同學(xué)送想要追求嬌嬌,但不認(rèn)識嬌嬌,就找戴勵同學(xué)幫其送禮物給嬌嬌,結(jié)果最后代理人戴勵與嬌嬌在一起了,卓賈易成了為別人做嫁衣。
題目:寫代碼來表示上述送禮物功能
2.1 版本一:沒有代理
版本一:沒有代理,讓追求者卓賈易直接送禮物給追求嬌嬌,類圖如下:
2.1.1 追求者與被追求者類
這里需要實(shí)現(xiàn)兩個(gè)類:
被追求者類,嬌嬌,目前題目中不需要有其它功能,僅維護(hù)一個(gè)自己的名字即可
追求者類,卓賈易,在實(shí)例化時(shí),傳入要追求的對象,并提供送禮物的接口,就是加句打印
// 被追求者
class SchoolGirl
{
public:
std::string name;
};
// 追求者
class Pursuit
{
public:
Pursuit(SchoolGirl mm)
{
m_mm = mm;
}
void GiveDOlls()
{
printf("%s 送你洋娃娃n", m_mm.name.c_str());
}
void GiveFlowers()
{
printf("%s 送你鮮花n", m_mm.name.c_str());
}
void GiveChocolate()
{
printf("%s 送你巧克力n", m_mm.name.c_str());
}
private:
SchoolGirl m_mm;
};
2.1.2 主函數(shù)
首先實(shí)例化一個(gè)被追求者,
然后實(shí)例化一個(gè)追求者,并傳入被追求者,然后依次調(diào)用追求者的送禮物接口。
#include <iostream>
int main()
{
// 被追求者
SchoolGirl jiaojiao;
jiaojiao.name = "嬌嬌";
// 追求者
Pursuit zhuojiayi = Pursuit(jiaojiao); // 嬌嬌并不認(rèn)識卓賈易,此處有問題
zhuojiayi.GiveDOlls();
zhuojiayi.GiveFlowers();
zhuojiayi.GiveChocolate();
return 0;
}
代碼運(yùn)行效果如下:
由于實(shí)際情況是,嬌嬌并不認(rèn)識卓賈易,因此不能直接將被追求者作為參數(shù)傳遞給給追求者。
下面來看版本二,使用代理,因?yàn)榇碚哒J(rèn)識嬌嬌。
2.2 版本二:只有代理
版本二與版本一的結(jié)構(gòu)基本一致,只是將追求者換成了代理人,類圖如下:
2.2.1 代理者與被追求者類
這里需要實(shí)現(xiàn)兩個(gè)類:
被追求者類,嬌嬌,僅維護(hù)一個(gè)自己的名字即可
代理者類,戴勵,在實(shí)例化時(shí),傳入要追求的對象,并提供送禮物的接口
// 被追求者
class SchoolGirl
{
public:
std::string name;
};
// 代理者
class Proxy
{
public:
Proxy(SchoolGirl mm)
{
m_mm = mm;
}
void GiveDOlls()
{
printf("%s 送你洋娃娃n", m_mm.name.c_str());
}
void GiveFlowers()
{
printf("%s 送你鮮花n", m_mm.name.c_str());
}
void GiveChocolate()
{
printf("%s 送你巧克力n", m_mm.name.c_str());
}
private:
SchoolGirl m_mm;
};
2.2.2 主函數(shù)
首先實(shí)例化一個(gè)被追求者,
然后實(shí)例化一個(gè)代理者,并傳入被追求者,然后依次調(diào)用追求者的送禮物接口。
#include <iostream>
int main()
{
// 被追求者
SchoolGirl jiaojiao;
jiaojiao.name = "嬌嬌";
// 代理人
Proxy daili = Proxy(jiaojiao); // 此時(shí)是代理者“戴勵”,追求者實(shí)例“卓賈易”又不在了
daili.GiveDOlls();
daili.GiveFlowers();
daili.GiveChocolate();
return 0;
}
代碼運(yùn)行效果如下:
版本二這種寫法,完全忽視了被代理者(追求者,卓賈易)的存在,也是不合實(shí)際的。
實(shí)際需求是要能體現(xiàn)禮物是追求者買的,代理是幫忙送禮物。
2.3 版本三:符合實(shí)際的代碼
版本三使用代理模式,類圖如下,定義一個(gè)接口類,來聲明需要代理來送的禮物類型,
然后追求者類(被代理人,卓賈易)和代理人類(戴勵)各自實(shí)現(xiàn)送禮物的具體接口,實(shí)現(xiàn)接口,用虛線+空心三角表示,
代理人的接口內(nèi)部,實(shí)際是調(diào)用被代理人的接口實(shí)現(xiàn),
這里代理人需要“知道”被代理人的各種代理需求,這種“知道”的關(guān)系屬于關(guān)聯(lián)關(guān)系,用實(shí)線(加箭頭)表示。
2.3.1 追求者、代理者與被追求者類
這里需要實(shí)現(xiàn)四個(gè)類:
被追求者類,嬌嬌,僅維護(hù)一個(gè)自己的名字即可
代理接口,IGiveGift,聲明需要代理的功能
追求者類,卓賈易,在(通過代理)實(shí)例化時(shí),傳入要追求的對象,并提供送禮物的接口,就是加句打印
代理者類,戴勵,在實(shí)例化時(shí),傳入要追求的對象,并提供送禮物的接口,其接口內(nèi)部是調(diào)用追求者類的具體實(shí)現(xiàn)
// 被追求者
class SchoolGirl
{
public:
std::string name;
};
// 代理接口
class IGiveGift
{
public:
virtual void GiveDolls(){};
virtual void GiveFlowers(){};
virtual void GiveChocolate(){};
};
// 追求者
class Pursuit : public IGiveGift
{
public:
Pursuit(SchoolGirl *mm)
{
m_mm = mm;
}
~Pursuit()
{
if(m_mm)
{
delete m_mm;
}
}
void GiveDolls()
{
printf("%s 送你洋娃娃n", m_mm->name.c_str());
}
void GiveFlowers()
{
printf("%s 送你鮮花n", m_mm->name.c_str());
}
void GiveChocolate()
{
printf("%s 送你巧克力n", m_mm->name.c_str());
}
private:
SchoolGirl *m_mm;
};
// 代理者
class Proxy : public IGiveGift
{
public:
Proxy(SchoolGirl *mm)
{
m_gg = new Pursuit(mm);
}
~Proxy()
{
if(m_gg)
{
delete m_gg;
}
}
void GiveDolls()
{
m_gg->GiveDolls();
}
void GiveFlowers()
{
m_gg->GiveFlowers();
}
void GiveChocolate()
{
m_gg->GiveChocolate();
}
private:
Pursuit *m_gg;
};
2.3.2 主函數(shù)
#include <iostream>
int main()
{
SchoolGirl *jiaojiao = new SchoolGirl();
jiaojiao->name = "嬌嬌";
Proxy daili = Proxy(jiaojiao);
daili.GiveDolls();
daili.GiveFlowers();
daili.GiveChocolate();
delete jiaojiao;
return 0;
}
代碼運(yùn)行效果如下:
總結(jié)
本篇介紹了設(shè)計(jì)模式中的代理模式,并通過代理人替被代理人送禮物的實(shí)例,使用C++編程,來演示代理模式的使用。