簡體   English   中英

C++:替換 Singleton

[英]C++: Replacement for Singleton

我經常使用單例,因為我討厭將主 class 的 object 傳遞給成員類,以允許他們訪問主 class。

Class Foo
{
    A* a;
    B* b;
    C* c;
};

For example in the above example if A,B and C would like to access Foo- I would have to pass the object of Foo each one of them, and store it as their member variable (or give the object in every function call). 這可行,但感覺不對,需要編寫更多代碼。

相反,我可以將 Foo 設為 singleton(當然只有在只有 1 個實例的情況下),然后從 A、B 和 C 調用 Foo::getInstance()->...。 而且我不必傳遞任何對象。 我覺得這很方便。

現在,問題是我有一個可能有多個 Foo 實例的情況。 顯然我不能使用 singleton 模式。 但我不想傳遞變量,也不想將它們存儲在成員類中。 代碼太多:)

例如,我討厭這樣:

A::A(Foo* foo) : m_foo(foo)
{

}

和這個:

void A::someFunc(Foo* foo, int someParam)
{

}

但是,我喜歡這個:

A::A()
{

}

void A::someFunc(int someParam)
{
    Foo* foo = Foo::getInstance();
}

還有其他方法嗎? 類似於 singleton 模式的東西?

這種模式正在創建一堆循環引用,這通常是代碼異味。 您可能需要仔細查看您的設計,因為解決此類關系問題的常用方法是創建與兩個現有類交互的第三個 class。 或者,如果您真的需要這種行為,那么傳遞對包含 class 的引用有什么問題?

使您的 singleton class成為template

template<unsigned int NUMBER>
class Foo
{
  A* a;
  B* b;
  C* c;
};

並使用任何你想要的實例。 它仍將保留為 singleton,但您可以擁有多個對象:

Foo<1>;
Foo<2>;
Foo<3>;

我已經在幾個項目中做到了這一點。 下面是一些偽代碼,讓您了解我是如何完成它的:

static map<string, Foo*> instances;

static Foo* Foo::getInstance(string name)
{
    Foo* inst = NULL;

    lock(instances);
    if(instances.count(name) > 0)
    {
        inst = instances[name];
    }
    else
    {
        inst = new Foo();
        instances[name] = inst;
    }

    unlock(instances);
    return inst;
}

然后你只需調用 Foo::getInstance("instance1") 或 Foo::getInstance("instance2") 等。你所要做的就是記住一個字符串,有點好(我認為)。 我不知道這種設計模式有沒有正式的名稱,如果有人請告訴我,這樣我以后在描述這個時就不會那么無知了。

單身人士是邪惡的,我們都同意。 但原因往往被遺忘。 這並不是因為它們本質上是全球性的。 全局變量在解決問題時很棒。 單例的問題在於它們結合了生命周期、初始化順序和全局訪問。

聽起來您需要一個全局變量,所以請使用全局變量。

A* g_a;
B* g_b;
C* g_c;

在其他任何東西需要訪問它們之前初始化 main 中的所有全局變量。

或者做得更聰明。

template< typename T >
T& instance( void );

template< typename T >
void set_instance( T& t );

void needs_an_A( void )
{
   instance<A>().a_stuff();
}

或者最好將它與 RAII 結合起來:

void needs_a_b( void )
{
   B& b = instance<B>();
   b.stuff();
   b.more_stuff();
}

int main()
{
   Initializer<A> init_a;
   Initializer<B> init_b;  // B needs an A during construction
   Initializer<C> init_c( "C constructor param" );

   needs_a_b();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM