1

Singleton クラスをどのように実装すべきかについて、私は 2 つの方法を実装しました。どちらを使用するのが最適な方法であるかについて、プログラマーの意見を求めたいだけです。

各メソッドは次のクラスを使用します。

class Animal {
public:
    virtual void speak() const = 0;
};

class Dog {
    virtual void speak() { cout << "Woof!!"; }
};

最初の方法:

class AnimalFactory {
public:
    static Animal* CreateInstance(int theTypeOfAnimal);

private:
    AnimalFactory() { };
    static int count; // this will be used to count the number of objects created
    static int maxCount; // this is the max count allowed.
};

int AnimalFactory::count = 0;
int AnimalFactory::maxCount = 1;

Animal* AnimalFactory::CreateInstance(int theTypeOfAnimal)
{
    Animal* pAnimal = NULL;

    if(pAnimal != NULL)
    {
        return pAnimal;
    }

    switch(theTypeOfAnimal)
    {
        case 0:
            pAnimal = new Dog();
            count++;
            break;

        case 1:
            pAnimal = new Cat();
            count++;
            break;

        case 2:
            pAnimal = new Spider();
            count++;
            break;

            default:
            cout << "Not known option";
    }

    return pAnimal;
}

2 番目の方法:

template<typename classType>
class Singleton {
public:
    classType& instance()
    {
        static classType object;
        return object;
    }
};

どんな意見でも感謝します、ありがとう:)!

4

8 に答える 8

4

ほとんどの場合、Singleton は悪用されます。一般的なアドバイスは次のとおりです。使用しないでください。シングルトンが正しい解決策である場合が本当にあると思う場合:確率はまだあなたに反対です。シングルトンを使用する必要があると本当に確信している場合でも、おそらくそれをある種の美化されたデータとして使用したいでしょう。それはあなたを傷つけるつもりです。

OK、警告されました。

2 番目のアプローチには、スレッド セーフであるという C++ 2011 の明確な利点があります。また、たまたまより単純です。

まだ C++ 2011 ロジックを実装していないコンパイラに行き詰まっていて、シングルトンをマルチスレッド アプリケーションで使用している場合は、アクセス関数が同時に呼び出された場合でも、シングルトンが 1 回だけ初期化されるようにする必要があります。 2 つのスレッド。もちろん、これは別の動作しない原因になります: 二重チェックのロック パターンを使用しないでください。それは[また]機能しません。機能するように実装した場合、誰かがやって来てコードを「修正」します。

于 2012-10-29T21:18:56.090 に答える
1

とにかく、組み込み環境では、singleton パターンは必要ありません。new や malloc も必要ありません。

説明するのは難しいですが、試してみます。

組み込みシステムは機能する必要があります。マニュアル、FAQ、インターネット フォーラムで武装した IT 部門はありません。Linux システムを調整する人も、構成を修正する人も、タスクのニーズに応じてより大きなハード ディスクやメモリをインストールする人もいません。あなたのプログラムは stderr と exit() に詳細なメッセージを意味のあるエラー コードとともに書き込むことができません。できたとしても、組み込みシステムが機能しないことを意味します。エラー時に赤色の LED を点滅させることができれば、何もないよりはましですが、それでもデバイスが故障したことを意味します。

malloc/free と new/delete を使用しないことをお勧めします。オブジェクトを静的配列として定義することにより、可能な最大数のオブジェクトを「事前に割り当てる」必要があります。または、アイテムの最大数がユーザーが変更できる構成に依存する場合は、プログラムの開始時に固定数のオブジェクトを割り当てて、30 分後ではなく起動時にメモリ不足の問題が発生するようにする必要があります。

はい、多くのメモリが無駄になりますが、不可解なエラーは発生しません。また、プログラムでメモリの問題に対処する必要はありません (起動時のみ)。

于 2012-10-30T14:01:52.877 に答える
0

最初の解決策には、いくつかの奇妙なコーディングがあります (Luchian Grigore の回答を参照)。それを無視してください:それはファクトリとシングルトンの間の概念の混合です。ファクトリは通常シングルトンですが、それが通常発行するものはそうではありません。

2番目のものは、クラスのオブジェクトを1つだけ作成できることを保証しますが、Singletonテンプレートでラップする場合に限ります. クラスに public コンストラクターがある場合は、スキームの外部で作成できるため、規則に違反する可能性があります。

私の本では、これらはどちらもシングルトンを行う良い方法ではありません。

少し拡張するには: シングルトンの考え方は、特定のものを管理する必要があり、1 つのコンポーネントが完全に責任を負う必要があるためです。

最初のバージョンでは、それぞれが 1 匹の動物を作成する複数の工場を持つことができます。現実世界では意味がなく、コードでも意味がありません。

2 番目の例では、すべての呼び出しを (オプションで) シングルトンにすることを許可しようとしていますが、すべてのクラスがそうである必要はなく、多くは「シングルトン化」されたときに必ずしも動作するとは限りません。

于 2012-10-29T21:12:44.157 に答える
0

関数を作成するだけで、頭痛の種全体を節約できるようです。

Animal * CreateAnimal(int theTypeOfAnimal)
{
    static int count = 0;
    static int maxCount = 1;

    switch(theTypeOfAnimal)
    {
        // ...
    }
}
于 2012-10-29T21:12:48.720 に答える
0

まあ、最初のものはうまくいきません:

Animal* pAnimal = NULL;
if(pAnimal != NULL)
{
    return pAnimal;
}

この状態が続くと思います?

私は前に2番目のものを見たことがあります.実際型。まあ、一般的な考え方は(シングルトンの場合)大丈夫ですが、私は次のようにします:

template<typename classType>
class AnimalManager {
public:
   static Animal& instance()
   {
       static classType object;
       return object;
   }
};

あなたが呼び出すことができる

Animal& animal = AnimalManager<Dog>::instance();
//assuming you derive Dog from Animal, which you're currently not
于 2012-10-29T21:12:49.983 に答える
0

レビューで、John Vlisides は、1 つの「パターン」が彼の GOF の本に含まれるべきではない場合、それはシングルトンであると述べました。ただし、C++ での実装に関する彼の議論も参照してください。

3 つの異なる作成モデル、4 つの異なるライフタイム モデル、および 2 つのスレッド モデルを使用してシングルトンを調査している Andrei Alexandrescu も参照してください。これは、シングルトンを実装する 24 の方法です。

個人的には、必要なオブジェクトのみを渡すことで、それらを回避するために最善を尽くしています。これにより、テストが容易になり、インターフェイスが明示的になります。などなど。警告を受けました。もちろん警告を受けましたが、耳を傾けますか?

于 2012-10-29T21:33:31.580 に答える
0

私は多くの Java プログラマーに軽蔑されますが、私は気にしません: プログラムに必要なオブジェクト インスタンスが 1 つだけであることがわかっている場合は、自由にグローバル オブジェクトを作成し、(を返す静的な get() メソッドを記述してください)。への参照) (他の場所からグローバル オブジェクトを参照しないでください)。

Java でのシングルトン パターンはグローバル オブジェクトを実装するための手法であり、C++ ではグローバル オブジェクトを非表示にするための手法であると思います。しかし、なぜ、それは隠されているときと同じくらい醜く、隠されていないのと同じくらい醜い.

また、他の通常のオブジェクトとしてシーンに表示されるように慎重にラップし、通常のオブジェクトとして処理する必要があります。おそらく、後でプログラムが進化するにつれて、それらのインスタンスが増え、通常のオブジェクトとして機能するようになるでしょう。

于 2012-10-29T21:31:53.717 に答える
0

最初のコード スニペットは、AnimalFactory::CreateInstance保持するインスタンス カウントを確認できないため、シングルトンの実装に失敗します。

2 番目のコード スニペット、

template<typename classType>
class Singleton {
public:
    classType& instance()
    {
        static classType object;
        return object;
    }
};

適切に行われると、Scott Meyers にちなんでMeyers' singletonと呼ばれます。

与えられたコードは機能しますが、厄介な使い方になります。インスタンス化を回避するSingletonには、instanceメソッドを宣言する必要がありますstaticclassTypeまた、によってのみインスタンス化できるというクラスの要件はSingleton、たとえば、例を含むコメントとして文書化する必要があります。

他の人はすでにシングルトンを使用しないように警告していますが、私もそうさせてください.

シングルトンには、たとえば Windows API の「ウィンドウ クラス」が 1 回だけ作成されるようにするなどの用途がありますが、主に変装したグローバル変数として悪用されます。グローバル変数の 1 つの問題、つまり、グローバル変数がいつ初期化されたかがわからない (C++ プログラミングでは静的初期化順序 fiascoと呼ばれる) ことは、シングルトンによって回避されます。しかし、主な問題は、それらがスパゲッティ通信システムとして機能し、混沌を誘発する情報を、決して疑わない場所の間で追跡不可能な方法でルーティングすることです.

だから、しないでください。

しかし、ロギング機能などのためにシングルトンが絶対に必要であることに気付いた場合は、Andrei Alexandrescu の"Modern C++ Design"でシングルトンの議論を読んでから、Loki ライブラリを手に入れて実行させてください。あなたのための仕事。

于 2012-10-30T05:00:13.523 に答える