當在實現機制中應用時,大部分有關循環依賴的鬆散都會混淆,而不是在程序包或模塊級別,還有一些來自Java測試框架的缺陷。由於Java對模因的影響,解決方案的表達方式與C++相反。目前還不清楚你是否試圖去除一個具體的循環依賴(代碼不能用C++編譯)或者有形而上的異議。
去耦混凝土循環依賴
一個成語在C++標準庫allocators被發現。
當你聲明的列表,以便:
std::list < int, my_allocator <int> >
分配器有一個嵌套結構,它允許訪問不同的專業化的原始模板,以便在std::list
實現可分配節點對象,而不僅僅是整數。
假設你有以下要求:
- 註冊表是全局的程序(即你不需要每個對象類型不止一個註冊表,否則你需要像工廠模式SingleShot建議,儘管在C++中,你通常會使用模板而不是虛擬函數多態);因此我傾向於使用靜態工廠而不是單身。
B
類的
- 對象應該只通過調用
A::CreateInstance(name)
A
作爲一個註冊表,所以反覆調用創建實例具有相同名稱返回相同的對象
- 代碼正確編譯沒有具體的循環引用創建
- 可以替換用於測試的註冊表或註冊類型的類型
此全局註冊表不需要任何關於它創建的類型的知識,除了它們提供了一個常量ructor採取參考一常量的std :: string:
#include <string>
#include <map>
template < class T = int >
class Registry {
static std::map<std::string,T*> map;
public:
static T& CreateInstance (const std::string& name) {
typename std::map< std::string, T* >::iterator it = map.find (name);
if (it == map.end())
return * (map [ name ] = new T (name));
else
return *it->second;
}
public:
template < typename U >
struct rebind {
typedef Registry<U> other;
};
};
template < class T >
std::map < std::string, T* > Registry<T>::map;
相應的登記對象提供私有構造和具有的CreateInstance功能的朋友:
template < typename R = class Registry<> >
class Registered {
typedef typename R::template rebind< Registered <R> > ::other RR;
private:
friend Registered<R>& RR::CreateInstance (const std::string& name);
explicit Registered (const std::string& name) {
// ...
}
Registered (const Registered<R>&) ; // no implementation
public:
void checkCondition()
{
bool condition = 7 > 5;
if (condition)
{
RR::CreateInstance ("whatever");
}
}
// ...
};
因爲rebind::other
成語,你不必編寫Registered<Registry<Registered<Registry ...
並避免具體的循環依賴。因爲默認Registry<int>
從未實際使用,除了提供rebind
,它沒有實例化,因此不報告,您可以不使用new int (name)
構建一個int錯誤。
然後,您可以使用類型爲你的B和A:
typedef Registered<> B;
typedef Registry<B> A;
int main() {
B& b1 = A::CreateInstance("one"); // create a B
b1.checkCondition(); // uses A to create object internally
B b2("two"); // compile error - can only create B using A
return 0;
}
當然你也可以建立一個Registered<MyMockRegistry>
進行測試,其他主要反對循環依賴類型。
爲什麼不能簡單地調用從B A :: CreateBInstances ::校驗條件? – Ozan 2009-09-16 04:13:15
如果類A是一個Singleton,爲什麼你不能只獲得單個實例並再次使用CreateBInstance? – 2009-09-16 04:13:58
這些建議忽略了基本的軟件依賴管理 - 它們在兩個類之間創建循環依賴關係。 – SingleShot 2009-09-16 04:20:41