web-dev-qa-db-ja.com

わかりました、グローバル変数は非難され、シングルトンは軽蔑されています、代替手段は何ですか?

つまり、デスクトップアプリケーションの場合。これは一般的な質問であり、一般的な回答のみが必要な場合があります。

38
mhd

静的データメンバーを持つ静的クラス?しかし、誰が気にします。静的データメンバーは、より政治的に正しいパッケージ化を備えた単なるグローバル変数です。

ファッションがあなたの常識を覆してはいけません。昔ながらのグローバル変数を使用しても問題はありません。シングルトンパターンは、多くの場合、やり過ぎで入力するのが面倒であり、コードをシングルステップでデバッグするときに面倒です。

C/C++を使用していると仮定すると、ヒープからメモリを割り当てるクラスインスタンスであるグローバル変数を使用しないことをお勧めします。それらは、メモリリークをチェックするツールの使用を困難にします。グローバルをポインタとして宣言し、main()の最初で新しく、最後で削除します。

6つのコメントの後で編集:ロギングについて考えてください。アプリのどこからでもログに行を書き込めるようにしたいと思いませんか?そのロギングを行うためにグローバルに目に見えるものがない状態で、どの程度具体的にそれを達成しますか?グローバルに表示したい場合は、先に進んでグローバルに表示します。

36
Corey Trager

答えは言語によって異なります。私は最近、多くの人気のある携帯電話で動作するUSB​​スタックを開発している会社の人に会いました(たとえば、電話がコンピューターと通信できるようにするため)。彼らの店には、すべてのC手続きは再入可能でなければならないという規則があります。実際には、これが意味するのは、グローバル変数の代わりに、各ルーチンに追加のパラメーターを使用するということです。パラメータは、ルーチン間で持続する必要がある状態を指します。

私は常にこの手法を状態による抽象化に使用しています。例:写真画像のリーダーの抽象化:リーダーは一度に1つのピクセルへのアクセスを提供します。開いているファイル記述子、画像内の現在の位置などを知っている必要があります。そのすべての情報は、プライベートC構造体またはC++クラスのプライベートメンバーに送られます。グローバル変数はありません。外の世界は見ています:

typedef struct Pnmrdr_T *Pnmrdr_T;

struct Pnmrdr_T *Pnmrdr_new(FILE *);
pixel Pnmrdr_get(Pnmrdr_T);
void Pnmrdr_close(Pnmrdr_T);
void Pnmrdr_free(Pnmrdr_T *rp); // frees memory and sets *rp = NULL

このスタイルのプログラミングは、OOメソッド)と非常によく似ています。

なぜグローバル変数よりも優れているのですか? 驚きはありません。何か問題が発生した場合、または機能を追加したい場合は、渡された値ですべてが明示的であることを知っています。さらに、多くのモジュールを一緒にプラグインでき、それらの間で明示的に状態を渡さない限り、それらは干渉しません。携帯電話業界での私の連絡先によると、このプロパティは彼の会社にとって巨大でした---彼らはOEMソフトウェアの衣装であり、さまざまなクライアントのためにさまざまな部品を簡単に接続できます。

私はこの方法でプログラミングするのが本当に好きです。なぜなら、起こっていることすべてを見ることができ、私のプライベートデータ構造は詮索好きな目から保護されているからです:-)

17
Norman Ramsey

まず、単一化がグローバルよりも何らかの形で優れている、または受け入れられやすいというふりをする意味はありません。シングルトンは、OOPのように見えるようにドレスアップされたグローバルなものです。他にもたくさんの問題が投げ込まれています。

もちろん、代替手段はnotグローバルデータを持つことです。クラスがどこかの静的(グローバル)変数にアクセスする代わりに、データをコンストラクターに渡します。はい、コンストラクターにいくつかの引数を追加する必要があることを意味しますが、それは悪いことですか?これにより、クラスの依存関係が明示的になります。コンストラクターでクラスにさまざまなオブジェクトを提供するだけでクラスをテストできますが、グローバルデータに依存している場合は、それらのグローバルがテストに存在する必要があり、面倒です。

同様に、オブジェクトに直接渡されるもの以外にクラスへの魔法の依存関係がないため、簡単にリファクタリングできます。

すべてのオブジェクトが同じグローバルインスタンスと通信する必要がなくなるため、スレッドセーフの管理が容易になります。代わりに、クラスの個別のインスタンスを渡すことができます。

8
jalf

シングルトン変数またはグローバル変数が推奨されないかどうかは気にしません。それが最も論理的な実装方法だと思うなら、先に進んでそれを使用します。

3
Naveen

それはあなたが解決しようとしている問題に完全に依存します。この重要な情報はあなたによって省略されました。包括的なソリューションを探しているのなら、それはありません。該当する場合に適用するパターンがあります。

2
TheSoftwareJedi

グローバルとシングルトンの両方で私が見た最も一般的な懸念は、スレッドを使用するときに悪い動作をするリスクがあるということです。この場合、常に実行スコープをベースユニットとして使用する必要があります。これは、OOプログラミングの長所の1つです。オブジェクトメンバーを使用して、偶発的なスレッドの混乱をほとんど恐れずに、関連するすべてのデータを保持できます。これは、オブジェクト指向非対応のプログラミングとは対照的です。言語。パラメータを介してデータを渡す必要があります。

他の一般的な懸念は組織的なものになる傾向があります。データがいつでも読み取り/書き込みできる場合、大規模なシステムのどこからデータが取得されるかを正確に理解することは困難です。私の経験では、これはコード自体よりも開発者の問題です。難しい問題の例として主にプログラミングの本に登場するように見える1億行のメガシステムのいずれかに取り組んでいない限り、コードベース全体で特定のアイテムをかなり短い時間で検索できます。期間。必要な次のステップは、コードベースを定期的に監査して、グローバル/静的変数がランダムに割り当てられていないことを確認することです。これは多くの開発アプローチにとっては嫌悪感ですが、特定のサイズと複雑さのシステムにとっては、完全に実行可能なソリューションです。

1
Mike Burton

これに対する一般的な解決策は、シングルトン/グローバル変数の代わりにシングルインスタンスクラスを使用することです。

アプリケーションは、インスタンスが1つしかないことを確認する責任があります。

このソリューションは、人々がクラス(シングルトンではない)をインスタンス化するのを防ぐことができないため、ちょっとひどいです。したがって、それは内部クラスでなければなりません。

私はすべてについてあまり気にしません 宗教戦争 シングルトンパターンについてですが-それが私のニーズに合っていると思うなら、私は一般的にそれを使用します。

0
JohnIdol

グローバル変数は小さなプログラムでは問題ありませんが、大きくなると、誰かが変更を加えたり、「ああ、このグローバルを設定するだけで問題が解決する」と言ってバグを修正したりすると、奇妙な副作用が発生し始めます。

0
EddieD

グローバルとシングルトンを使用し、すべてが台無しになるのを見て、私はこの解決策を思いつきました。

  1. すべてのグローバル変数をクラスのメンバーにします。論理的には、すべてのグローバル変数はアプリケーション(またはシステム)に属します。アプリケーションクラスを作成するだけです。グローバルオブジェクトをプロパティとして定義します。したがって、最初に呼び出されたときに作成されます。

  2. アプリケーションクラスのシングルトンを作成して、グローバルにアクセスできるようにします。これは、コード内の唯一のシングルトンになります。結局のところ、Javaのsystem.outまたはsystem.inオブジェクトのようなものです。

注:これは非常に古い質問ですが、依然として人気があります。

0
bkilinc