web-dev-qa-db-ja.com

多くのシングルトンをリファクタリングする方法

私は中規模のpythonプログラム(約5000行のコード))を持っていますが、これは時間をかけて構築してきましたが、特に計画はありませんでした。は、5〜6個の大きなシングルトンオブジェクトで構成され、それぞれがデータベース通信、Webサーバー、データ収集クライアント、内部計算など、プログラムの特定の側面を処理します。

このようにいくつかのシングルトンを使用しても、OOプログラミングの真の利点を実際に活用していないと感じます。つまり、多数の関連オブジェクトを簡単に作成できます。私のシングルトンも互いにかなり依存しており、プログラムを大きく(たとえば、5万行程度)成長させた場合、私のアプローチがスパゲッティコードになることがわかります。

それで、私のプログラムを構造化するより良い方法があるかどうか疑問に思っています。例えば。シングルトンは実際には別のモジュールにする必要がありますか?しかし、シングルトンオブジェクトに非常にきちんと整理されている属性にどのようにアプローチすればよいでしょうか。他のアーキテクチャオプションはありますか?

私はデザインパターンにあまり詳しくないので(GOFの本は私のtodoリストに載っています)、おそらく私のプログラムに適したデザインパターンやアーキテクチャパターンがあるでしょうか。

7
funklute

シングルトンは多くの人にとって「邪悪」であると考えられており、シングルトンパターンにはその用途がありますが、その数はわずかですが...いくつかの大規模なコードベースで作業してきましたが、ほとんどの場合、それらをシングルトンから遠ざけています。

シングルトンを削除する最も簡単な方法は次のとおりです。

  1. シングルトンの上にインターフェースを導入:これにより、契約を実装から分離し、実際の実装への結合を減らすことができます
  2. ユニットテストからシングルトンインスタンスを設定できるように、シングルトンにセッターを提供します:これにより、ユニットテストでシングルトンインスタンスを「スワップアウト」できます。
  3. 変更するクラスでユニットテストを作成する:1で導入されたインターフェースのモックと2で導入されたセッターを使用して、クラスでユニットテストを作成できるようになりました。
  4. 静的に取得するのではなく、シングルトンを挿入します:シングルトンに依存するクラスで、(1で作成したインターフェイスを介して)シングルトンを挿入する方法があります。コンストラクターインジェクション、メソッドベースのセッターを使用できます。リファクタリングしているクラスに実際に触れるのはこれが初めてです! 3で導入されたテストは、何も壊さずにリファクタリングするのに役立ちます

「オールイン」する場合は、ステップ2を回避できますが、このアプローチは、何も壊れていないことを確認するテストを持たないクラスを変更しないようにするという意味で最も純粋です。個人的には、これは少しやりすぎですがYMMVです。基本的な前提は、静的にフェッチされるのではなく、依存関係が注入されたクラスに向かって移動することです。

また、シングルトンの正当な使用法がある場合でも、それらを注入する必要があります。シングルトンとは、特定のクラスの単一のインスタンスのみが存在することを保証することです。グローバルにアクセス可能な静的関数を持つ古典的なパターンはこれを実現しますが、残念なことに、サンプルコードがウェブ上に浮かんでいるため、そのインスタンスを挿入する必要がなくなります。依存関係の注入を処理できるフレームワークはたくさんあります。それらのほとんどには、アプリケーション全体で同じインスタンスが再利用されるようにオブジェクトを構成する方法があり、事実上これをシングルトンにします。

23
JDT

シングルトンの恐怖は非常に誇張されています。確実に、いくつかの大きな構成要素の1つが必要な場合は、それらを使用しても問題はありません。 (代わりに静的モジュールを作成したいが、言語で許可されていない場合は、プログラムではなく、言語に問題がある可能性があります。)

シングルトンに対する一般的な議論は、単体テストを模倣するのが難しいということです。ただし、これは、コードでクラスをハードコーディングした場合にのみ適用されます。シングルトンパターンは、1つのインスタンス特定のクラスののみが存在することを確認することに本当に関係しています。 eachがシングルトンであるサービスインターフェースの複数の実装を妨げるものはなく、ビジネスやテストの目的で必要に応じてそれらをスワップ/インジェクト/動的にロードします。

12
Kilian Foth