web-dev-qa-db-ja.com

依存性注入と静的メソッド

今日、別の開発者と、文字列を受け入れて文字列を出力するメソッドを使用してクラスにアプローチする方法について、興味深い議論をしました。

例の目的のために完全に構​​成されている次のようなものを想像してください

public string GetStringPart(string input)
{ 
   //Some input validation which is removed for clarity

   if(input.Length > 5)
        return input.Substring(0,1);

   if(input.Substring(0,1) == "B")
        return input.Substring(0,3);

   return string.empty;
}

文字列入力に基づくロジックを持つ関数は、DIを使用してプロジェクトに追加され、DIコンテナーが配置されます。この新しいクラスにインターフェイスを追加して、必要な場所に挿入しますか、それとも静的クラスにしますか?それぞれの長所と短所は何ですか?どこで必要なときにアクセスするだけでなく、コンストラクターインジェクションでこれを使用する必要があるのか​​(またはしないのか)。

21
James

これを注入する必要がある理由はありません。これは単なる関数であり、依存関係がないため、呼び出すだけです。純粋に見えるので、必要に応じて静的にすることもできます。これに対する単体テストを難なく書くことができます。他のクラスで使用されている場合でも、単体テストを作成できます。

依存関係のない関数を抽象化する必要はありません。それはやりすぎです。

これがより複雑になった場合は、おそらくコンストラクタまたはメソッドにインターフェースを渡す必要があります。しかし、場所などに基づく複雑なGetStringPartロジックがない限り、その道を進むことはありません。

27
Jon Raynor

ここに理由があります

class DOSClient {
    OrderParser orderParser;
    string orderCode;

    DOSClient(OrderParser orderParser, string ordercode) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
    }
    void DisplayOrderCode() {
        Console.Write( "Prefix: " + orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

class GUIClient {
    OrderParser orderParser;
    string orderCode;
    GUI gui;

    GUIClient(OrderParser orderParser, string ordercode, GUI gui) { 
        this.orderParser = orderParser; 
        this.ordercode = ordercode;
        this.gui = gui;
    }

    void DisplayOrderCode() {
        gui.Prefix( orderParser.GetStringPart(ordercode) ); 
        ...
    }
}

class OrderParserUS : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 5)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "B")
            return input.Substring(0,3);

        return string.empty;
    }
}

class OrderParserEU : IOrderParser {

    public string GetStringPart(string input)
    { 
        //Some input validation which is removed for clarity

        if(input.Length > 6)
            return input.Substring(0,1);

        if(input.Substring(0,1) == "#")
            return input.Substring(0,3);

        return string.empty;
    }
}

静的メソッドを使用していた場合、GetStringPartの動作を変更するには、古い動作を破壊するか、条件付きロジックでそれを汚染する必要があります。静力学が変装した邪悪なグローバルであることは事実ですが、それらが多態性を無効にするという事実は、それらについての私の主な不満です。静的メソッドはOOP言語では最初のクラスではありません。メソッドに状態を持たないオブジェクトでも、メソッドを移植可能にすることで、メソッドを移植可能にします。その動作は、変数の値。

ここでは、ヨーロッパで展開したときと米国で展開したときの動作が少し異なるシステムを想像しました。どちらか一方のシステムに、もう一方が必要とするコードのみを含めるように強制します。クライアントに挿入される解析オブジェクトの順序を制御することで、動作を変更できます。これにより、地域の詳細の広がりを抑えることができます。また、既存のパーサーに手を加える必要なく、OrderParserCanadaを簡単に追加できます。

それがあなたにとって何の意味もないのであれば、これについての良い議論は実際にはありません。

ところで、GetStringPartはひどい名前です。

12
candied_orange