7

現在、DI/IOC を使用しており、追加のパラメーターをコンストラクターに渡す必要がある場合は、ファクトリ クラスを使用します。

public class EmailSender 
{
    internal EmailSender(string toEmail, string subject,String body, ILogger emailLogger)
    {.....} 
}

public class EmailSenderFactory
{
    ILogger emailLogger;
    public EmailSenderFactory(ILogger emailLogger)
    { 
        this.emailLogger = emailLogger;
    }
    public EmailSender Create(string toEmail, string subject, string body) 
    {
        return new EmailSender(toEmail, subject, body, emailLogger);
    }
}

ここでの問題は、大量のファクトリ クラスを作成することになり、人々はそれらの使用方法を常に知っているとは限らないことです (彼らは自分でそれらを新しくすることもあります)。このようにクラスをコーディングすることの最大の欠点は何ですか:

public class EmailSender 
{
    EmailLogger logger = IoC.Resolve<ILogger>();
    internal EmailSender(string toEmail, string subject,String body)
    {.....} 
}

長所: ファクトリ クラスを必要とせずにコンストラクターを安全に使用できるようになりました。短所: Service Locator を参照する必要があります (テスト容易性については心配していません。コンテナーのバッキング サービスとしてモック コンテナーを使用するのは簡単です)。

これをすべきではない理由の大きな悪臭がそこにありますか?

編集:少し考えた後、プライベートコンストラクターを持ち、Factory クラスをネストすることで、実装とファクトリーを一緒に保ち、人々がクラスを不適切に作成するのを防ぐことができると思いました。SL が汚れていることについてのすべてのポイントはもちろん真実なので、以下の解決策は私を満足させます。

public class EmailSender 
{
    public class Factory
    {
        ILogger emailLogger;
        public Factory(ILogger emailLogger)
        { 
            this.emailLogger = emailLogger;
        }
        public EmailSender Create(string toEmail, string subject, string body) 
        {
            return new EmailSender(toEmail, subject, body, emailLogger);
        }
    }
    private EmailSender(string toEmail, string subject,String body, ILogger emailLogger)
    {
    } 
}
4

3 に答える 3

14

はい - 悪いです。

  • フレームワークに仕事をさせることができるのに、なぜそんなに多くのコードを書くのでしょうか? すべての IoC.Resolve() 呼び出しは不要であり、それらを記述する必要はありません。
  • もう 1 つのさらに重要な側面は、コンポーネントがサービス ロケーターに関連付けられていることです。

    コンポーネントを使用する必要があるたびに、完全にセットアップされたサービスロケーターが必要です。

  • 最後になりましたが、少なくとも、SL コードがコードベース全体に散らばっていますが、これは良いことではありません。何かを変更したい場合、複数の場所を調べなければならないからです。
于 2009-10-23T08:15:28.007 に答える
2

私が考えることができる最大の理由は (一般的なサービス ロケーターの問題を見るだけではありません)、それがあなたのクラスのユーザーとしての私が期待するものではないということです。

メタ ディスカッション:
一部の DI フレームワーク ( Guiceなど) は、ファクトリを構築します

一部の人々は、「注射可能」から「新規可能」を分離することを提唱しています。

于 2009-10-23T08:35:09.653 に答える
1

Krzysztof によるこの強い「悪い」という回答についてはよくわかりません。それらを絶対に悪いか良いかで分類することなく、そこにはいくつかのトレードオフと好みがあると思います.

  • IoC.Resolve() 呼び出しを記述することは、注入メカニズム用の特定のコンストラクターまたはプロパティを記述することよりも不必要だとは思いません。
  • これは、サービス Locator に関連付けられており、クラスをインスタンス化する前に設定する必要があることに同意する必要があります。でも:
    • より具体的なインターフェイスを使用して、サービス ロケーターを分離できます。これにより、システムのすべてのサービスの巨大なサービス ロケータとの結合を減らします
    • ええ、DI メカニズムを使用する場合は、これらの IoC.Resolve() をすべて削除しますが、「メイン」サービスをインスタンス化するために一種のコンテナーを使用する必要があります。DI はそれらの呼び出しを傍受する必要がありますね。
    • あなたのサービスロケータは、「自動設定可能」であるか、少なくともセットアップが非常に簡単である可能性があります(すべきですか?)。
  • 上記の「より具体的なインターフェースでサービスロケーターを分離する...」ポイントを参照してください。

サービスロケーターを使用すると、コンストラクターを介して依存関係を公開するのではなく、実際に依存関係をクラス内に隠していると思います。また、サービスロケーターが構成されずに呼び出されるまで、クラスに何かが欠けていることがわからないため、私の意見では不便です。

しかし、DI には、そのようなコードの闇がないわけではありません。DI を使用する場合、それらの依存関係がコンストラクターにどのように「出現」したか (DI マジック) を理解することは、実際には明らかではありません。SL を使用することで、少なくともそれらの依存関係がどこから来ているかを確認できます。

それでも、コンストラクターへの依存関係を公開するクラスをテストする場合、(ほとんど) 見逃すことはできません。これは、サービス ロケータを使用する場合には当てはまりません。

私はクシシュトフが間違っていたと言っているわけではありません。しかし、サービス ロケーターを使用することは、必ずしも悪い "設計" ではなく、単に悪いというわけでもありません。

フィル

于 2009-11-04T18:02:34.600 に答える