限制你的友元類數(shù)量
也許你遇到過這樣的情況:
在一個(gè)類有一組策略,而且這組策略的實(shí)現(xiàn)都需要訪問A的一些成員,而且這些成員并不希望被其它類所訪問。
一般這些成員被期望設(shè)置為保護(hù)或者私有的,并且這組策略被當(dāng)作這個(gè)類A的友元類。如:
Code
class Strategy1;
class Strategy2;
class Strategy3;
class A
{
public:
friend class Strategy1;
friend class Strategy2;
friend class Strategy3;
private:
void _foo();
int _bar;
};
現(xiàn)在,假如你需要添加新的策略Strategy4為了維持這種微妙的關(guān)系,你需要把Strategy4添加為類A的新的友元類。
隨著策略的增加,這個(gè)過程不斷擴(kuò)展A的友元類,最終你恐怕不會(huì)喜歡你看到的代碼。并且由于每次增加策略都需要使得依賴A的代碼重新編譯,這里一定有什么不妥之處。
我想到一種解決方法,可以讓你的代碼看上去不算太混亂。
首先,既然這組策略以相似的情況出現(xiàn)在A的周圍,那么它們可能有相似之處。比如它們可能需要訪問A的同一部分成員。
那么假如通過一個(gè)代理類來訪問這些成員,那么這組策略就不必都是A的友元,只要這個(gè)代理是A的友元即可。
這個(gè)代理我稱之為友元接口。
Code
class IFriendA_Strategy;
class A
{
public:
friend class IFriendA_Strategy;
private:
void _foo();
int _foo2(int p) const;
int _bar;
};
class IFriendA_Strategy
{
protected:
typedef IFriendA_Strategy Friend; // 統(tǒng)一友元接口的訪問方式
// 想必這組函數(shù)的實(shí)現(xiàn)不必給出了吧來源:
static void _foo(A& rA);
static int _foo2(const A& rA, int p);
static int get_bar(const A& rA);
static void set_bar(const A& rA, int value);
};
class Strategy1 : protected IFriendA_Strategy
{
public:
void x(A &ra, int p)
{
// 于是你可以訪問了
Friend::_foo(ra);
int f = Friend::_foo2(ra, p);
Friend::set_bar(ra, Friend::get_bar(ra) + f);
}
};
如此一來,既完成了友元關(guān)系,又減少了依賴關(guān)系。
缺點(diǎn)在于代碼不具備防御性,非授權(quán)類可以輕易的獲得訪問A保護(hù)成員的能力。只需要從友元接口繼承即可。
這里再進(jìn)一步可以看到,如果類A有多組不同方面的策略,這些策略需要訪問A的成員的不同子集,那么它們可以獨(dú)立的歸到各自的友元接口上,互不相干。
也許你遇到過這樣的情況:
在一個(gè)類有一組策略,而且這組策略的實(shí)現(xiàn)都需要訪問A的一些成員,而且這些成員并不希望被其它類所訪問。
一般這些成員被期望設(shè)置為保護(hù)或者私有的,并且這組策略被當(dāng)作這個(gè)類A的友元類。如:
Code
class Strategy1;
class Strategy2;
class Strategy3;
class A
{
public:
friend class Strategy1;
friend class Strategy2;
friend class Strategy3;
private:
void _foo();
int _bar;
};
現(xiàn)在,假如你需要添加新的策略Strategy4為了維持這種微妙的關(guān)系,你需要把Strategy4添加為類A的新的友元類。
隨著策略的增加,這個(gè)過程不斷擴(kuò)展A的友元類,最終你恐怕不會(huì)喜歡你看到的代碼。并且由于每次增加策略都需要使得依賴A的代碼重新編譯,這里一定有什么不妥之處。
我想到一種解決方法,可以讓你的代碼看上去不算太混亂。
首先,既然這組策略以相似的情況出現(xiàn)在A的周圍,那么它們可能有相似之處。比如它們可能需要訪問A的同一部分成員。
那么假如通過一個(gè)代理類來訪問這些成員,那么這組策略就不必都是A的友元,只要這個(gè)代理是A的友元即可。
這個(gè)代理我稱之為友元接口。
Code
class IFriendA_Strategy;
class A
{
public:
friend class IFriendA_Strategy;
private:
void _foo();
int _foo2(int p) const;
int _bar;
};
class IFriendA_Strategy
{
protected:
typedef IFriendA_Strategy Friend; // 統(tǒng)一友元接口的訪問方式
// 想必這組函數(shù)的實(shí)現(xiàn)不必給出了吧來源:
static void _foo(A& rA);
static int _foo2(const A& rA, int p);
static int get_bar(const A& rA);
static void set_bar(const A& rA, int value);
};
class Strategy1 : protected IFriendA_Strategy
{
public:
void x(A &ra, int p)
{
// 于是你可以訪問了
Friend::_foo(ra);
int f = Friend::_foo2(ra, p);
Friend::set_bar(ra, Friend::get_bar(ra) + f);
}
};
如此一來,既完成了友元關(guān)系,又減少了依賴關(guān)系。
缺點(diǎn)在于代碼不具備防御性,非授權(quán)類可以輕易的獲得訪問A保護(hù)成員的能力。只需要從友元接口繼承即可。
這里再進(jìn)一步可以看到,如果類A有多組不同方面的策略,這些策略需要訪問A的成員的不同子集,那么它們可以獨(dú)立的歸到各自的友元接口上,互不相干。