1つの実装を構築する多数。DI絶望?サービスロケーターを使用しますか?


14

インジェクションを受け入れるのではなく、依存関係を直接構築するクライアントが1001人いるとします。上司によると、1001のリファクタリングはオプションではありません。実際には、ソースへのアクセスさえ許可されていません。クラスファイルだけです。

私たちがやるべきことは、これらの1001クライアントが通過するシステムを「近代化」することです。好きなことをリファクタリングできます。依存関係はそのシステムの一部です。そして、それらの依存関係のいくつかは、新しい実装を行うために変更することになっています。

私たちがやりたいことは、この多数のクライアントを満たすために、依存関係の異なる実装を構成する機能を持っていることです。悲しいことに、クライアントはコンストラクターまたはセッターによるインジェクションを受け入れないため、DIはオプションのようには見えません。

オプション:

1)クライアントが使用するサービスの実装をリファクタリングして、クライアントが現在必要としていることを行うようにします。完了です。柔軟ではありません。複雑ではありません。

2)実装をリファクタリングして、ファクトリを通じて取得したさらに別の依存関係に作業を委任します。これで、ファクトリをリファクタリングすることで、すべてが使用する実装を制御できます。

3)実装をリファクタリングして、作業をサービスロケーターを介して取得したさらに別の依存関係に委任します。これhashmapで、少しのキャストが行われたオブジェクトへの文字列である可能性のあるサービスロケーターを構成することで、すべてが使用する実装を制御できます。

4)まだ考えていないこと。

目的:

設計が不十分な古いクライアントコードを無意味な複雑さを加えることなく未来にドラッグすることによって引き起こされる設計の損傷を最小限に抑えます。

クライアントは依存関係の実装を知っていないか制御するべきではありませんが、で構築することを主張しますnew。制御することはできませんnewが、構築しているクラスを制御します。

私の質問:

何を考慮しなかったのですか?


Doc Brownからの質問

異なる実装間で構成する可能性が本当に必要ですか?何のために?

機敏。未知の多く。経営陣は変化の可能性を望んでいます。外の世界への依存を失うだけです。またテスト。

実行時の仕組みが必要ですか、それとも異なる実装を切り替えるためにコンパイル時の仕組みが必要ですか?どうして?

コンパイルの時間の仕組みで十分です。テストを除く。

どの粒度で実装を切り替える必要がありますか?一斉に?モジュールごと(それぞれがクラスのグループを含む)?クラスごと?

1001のうち、一度に実行されるのは1つだけです。すべてのクライアントが一度に使用するものを変更しても問題はないでしょう。ただし、依存関係を個別に制御することはおそらく重要です。

誰がスイッチを制御する必要がありますか?あなた/あなたの開発者チームのみ?管理者ですか?各クライアントは自分で?または、クライアントのコードのメンテナンス開発者ですか?それでは、メカニックはどれほど簡単/堅牢/完全に機能する必要があるのでしょうか?

テスト用の開発。外部ハードウェアの依存関係が変化するため、管理者。テストと構成が簡単である必要があります。


私たちの目標は、システムを迅速に作り直し、近代化できることを示すことです。


実装スイッチの実際の使用例

1つは、ハードウェアソリューションの準備が整うまで、一部のデータがソフトウェアによって提供されることです。


1
工場やロケーターをグローバルな状態で保管することで、多くのことを達成できるとは思いません。なぜわざわざ?依存関係を代用してクライアントをテストしますか?
バシレフ

カスタムクラスローダーの使用を検討してください。
バシレフ

好奇心から、このシステムは何をしていますか?
プライム

回答:


7

まあ、サポートされているソリューションの技術的な詳細とそれらの正確な違いを完全に理解しているわけではありませんが、私見ではまずどのような柔軟性が本当に必要なのかを知る必要があります。

自問しなければならない質問は次のとおりです。

  • 異なる実装間で構成する可能性が本当に必要ですか?何のために?

  • 実行時の仕組みが必要ですか、それとも異なる実装を切り替えるためにコンパイル時の仕組みが必要ですか?どうして?

  • どの粒度で実装を切り替える必要がありますか?一斉に?モジュールごと(それぞれがクラスのグループを含む)?クラスごと?

  • 誰がスイッチを制御する必要がありますか?あなた/あなたの開発者チームのみ?管理者ですか?各クライアントは自分で?または、クライアントのコードのメンテナンス開発者ですか?それでは、メカニックはどれほど簡単/堅牢/完全に機能する必要があるのでしょうか?

これらの質問への回答を念頭に置いて、考えられる最も簡単なソリューションを選択してください。必要な柔軟性が得られます。追加の努力を意味する場合は、「万が一に備えて」わからない柔軟性を実装しないでください。

回答への返信として:少なくとも1つの実際のユースケースが手元にある場合は、それを使用して設計上の決定を検証します。そのユースケースを使用して、どの種類のソリューションが最適かを見つけてください。「工場」または「サービスロケーター」が必要なものを提供してくれる場合、または何か他のものが必要な場合に試してみてください。両方のソリューションがあなたのケースに等しく適していると思うなら、サイコロを投げてください。


良い質問です!アップデートをご覧ください。
candied_orange

実際の使用例で更新されました。
candied_orange

@CandiedOrange:魚をあげることはできません。自分で釣りを手伝おうとするだけです:
Doc Brown

わかった。私は水を見つめているだけで、もっと良い餌が必要なのか、それとも別の釣りの穴が必要なのか疑問に思っている。適切なDIを実行したいのですが、この状況ではそれができないようです。
candied_orange

1
@CandiedOrange他の何よりも「良い」または「良い」ので、DIをしたいという欲求にこだわらないでください。DIは、問題に対する特定の解決策の1つです(またはいくつかの場合があります)。しかし、それは常に最も「適切な」ソリューションではありません。それに恋してはいけない...それはそれのように扱います。それはツールです。
svidgen

2

これが正しいことを確認するためです。たとえばC1,...,Cn、いくつかのクラスで構成されるサービスと、を直接呼び出す多数のクライアントがありますnew Ci(...)。だから私はあなたのソリューションの一般的な構造に同意すると思います。D1,...,Dnそれは素敵でモダンないくつかの新しいクラスで新しい内部サービスを作成し、それらの依存関係を挿入し(スタックを通じてそのような依存関係を許可します)、その後Ci、インスタンス化とに委任するDi。質問はそれを行うと、あなたがカップルの方法を提案する方法である23

同様の提案をする2。全体Diおよび内部で依存性注入を使用しR、オブジェクトグラフを組み立てる通常の構成ルートを作成できます(適切と思われる場合はフレームワークを使用します)。R静的なファクトリーの背後に押し込み、それぞれCiがそれDiを通過できるようにします。たとえば、あなたは

public class OldClassI {
    private final NewClassI newImplementation;

    public OldClassI(Object parameter) {
        this.newImplementation = CompositionRoot.getInstance().getNewClassI(parameter);
    }
}

基本的にこれはソリューション2ですが、残りの依存性注入とともにすべての工場を1つの場所に収集します。


私はこれに賛同する。これがオプション3のサービスロケーターとどのように異なるかがわからないだけgetInstance()です。各呼び出しで新しいインスタンスを構築する予定ですか?
candied_orange

@CandiedOrangeこれはおそらく使用法の単なる衝突です。私にとって、サービスロケーターは本質的に型からオブジェクトへのハッシュマップにすぎません。これに対して、コンポジションルートは他のオブジェクトを構築するメソッドの束を持つオブジェクトです。
walpen

1

シンプルで空想のない、単一の実装から始めます。

後で追加の実装を作成する必要がある場合は、実装の決定がいつ行われるかが問題になります。

「インストール時」の柔軟性が必要な場合(各クライアントのインストールは単一の静的実装を使用します)、まだ特別なことをする必要はありません。異なるDLLまたはSO(またはlib形式が何であれ)を提供するだけです。クライアントは正しいものをlibフォルダに入れるだけで...

実行時の柔軟性が必要な場合は、シンアダプターと実装選択メカニズムが必要です。工場、ロケーター、またはIoCコンテナーのいずれを使用するかは、ほとんど意味がありません。アダプターとロケーターの唯一の重要な違いは、A)命名とB)返されたオブジェクトがシングルトンまたは専用インスタンスのどちらであるかです。そして、IoCコンテナーとファクトリー/ロケーターの大きな違いは、誰が誰を呼び出すかです。(多くの場合、個人的な好みの問題です。)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.