[OOD-More C++ Idioms] 律師與委託人 (Attorney-Client)
律師與委託人 (Attorney-Client)
目的
控制訪問類實現細節的粒度。
動機
C++中的friend會開始類內部的所有細節,也因此破壞了封裝性。C++沒有提供可以選擇性使用某一部分私有成員的方式,要麼全部開放,要麼全部拒絕。例如下面例子中的類Foo宣告Bar為其友元,可以訪問它的所有私有成員。這樣增加了耦合性,類Bar也無法單獨釋出,這樣並不太合適。
class Foo
{
private:
void A(int a);
void B(float b);
void C(double c);
friend class Bar;
};
class Bar {
// 這個類只需要使用Foo::A和Foo::B.
// 但它其實可以訪問Foo所有的成員.
};
如果能選擇確定需要使用到的一組成員,而不是全部,就可以降低耦合性。而這個律師與委託人的慣用法就可以精準的控制友元所能使用的成員。
解決方案及示例
基本思路是增加一箇中間層進行控制。一個客戶類可以指定一個律師(Attorney)類作為其友元類,再由此律師類擔當其它類使用客戶類的代理。與典型的代理(proxy)類不同的是,律師類會限制一個可以使用的成員子集。比如上面的例子中,將Foo改為Client, 再提供一箇中間類限制只允許訪問Client::A和Client::B。程式碼如下:
class Client
{
private:
void A(int a);
void B(float b);
void C(double c);
friend class Attorney; // 這裡指定友元類
};
class Attorney {
private:
static void callA(Client & c, int a) {
c.A(a);
}
static void callB(Client & c, float b) {
c.B(b);
}
friend class Bar;
};
class Bar {
// 現在Bar通過Attorney類就只能使用Client::A和Client::B了。
};
類圖如下:
Attorney類只有私有的inline static函式,每個都持有一個Client例項的引用,再轉而呼叫合適的方法。僅保持私有實現,可以避免被其它類使用。所有需要使用Client都要在Attorney中宣告為友元類。如果沒有Attorney類,就需要直接修改Client類。
另外還可以使用多個律師(Attorney)類分離出對不同私有實現的訪問。
還有一個有趣的案例是提供一個律師(Attorney)類作為多個類的中間人(mediator),來統一提供對它們私有實現的訪問。這個設計可以用於解決C++中無法繼承友元類所帶來的問題,因為私有實現的虛擬函式是可以被基類呼叫的。 下面這個例子裡,Derived::Func是一個多型實現。通過這個慣用法同樣可以使用到Derived中的私有實現。
#include <cstdio>
class Base {
private:
virtual void Func(int x) = 0;
friend class Attorney;
public:
virtual ~Base() {}
};
class Derived : public Base {
private:
virtual void Func(int x) {
printf("Derived::Func\n"); // 雖然沒有繼承基類中的友元關係,但仍然可以被訪問。
}
public:
~Derived() {}
};
class Attorney {
private:
static void callFunc(Base & b, int x) {
return b.Func(x);
}
friend int main (void);
};
int main(void) {
Derived d;
Attorney::callFunc(d, 10);
}
類圖如下:
已知的應用
參考
相關文章
- [OOD-More C++ Idioms] 內部類 (Inner Class)C++
- [OOD-More C++ Idioms] 寫時拷貝 (Copy on Write)C++
- 委託與事件-委託詳解(一)事件
- C++:關於委託類C++
- 重中之重:委託與事件事件
- C#委託與事件C#事件
- C# - 委託與事件C#事件
- 委託、Lambda表示式、事件系列05,Action委託與閉包事件
- 委託、事件--委託例項篇事件
- 委託
- C#自學(一)委託(delegate)、委託泛型、多播委託C#泛型
- Js 事件原理與事件委託JS事件
- C# 之委託與事件C#事件
- 委託、Lambda表示式、事件系列04,委託鏈是怎樣形成的, 多播委託, 呼叫委託鏈方法,委託鏈異常處理事件
- 事件委託事件
- 委託、Lambda表示式、事件系列01,委託是什麼,委託的基本用法,委託的Method和Target屬性事件
- 委託與事件-事件詳解(二)事件
- 詳解C#委託與事件C#事件
- 委託、Lambda表示式、事件系列07,使用EventHandler委託事件
- jQuery 事件委託jQuery事件
- 委託筆記筆記
- .NET委託解析
- Java-委託Java
- C#委託C#
- 4.7 委託權益人證明機制——DPoS
- C# 委託(delegate)、泛型委託和Lambda表示式C#泛型
- 代理模式與Kotlin中的委託模式模式Kotlin
- C#.Net築基-解密委託與事件C#解密事件
- C#-委託delegateC#
- winform實現委託ORM
- C# 事件委託C#事件
- C#委託(delegate)C#
- C#事件委託事件
- C# 委託事件C#事件
- wpf移除事件委託事件
- 觀察者模式與.Net Framework中的委託與事件模式Framework事件
- dotnet 委託的實現解析(2)開放委託和封閉委託 (Open Delegates vs. Closed Delegates)
- 委託、Lambda表示式、事件系列03,從委託到Lamda表示式事件