web-dev-qa-db-ja.com

コンストラクターの代わりに静的メソッドを使用するのはいつですか?

私はあなたに短い質問があります:これに似たクラスがあるとしましょう。

public class StreamTradeDataProvider : ITradeDataProvider
{
    public StreamTradeDataProvider(Stream stream)
    {
        this.stream = stream;
    }

    public IEnumerable<string> GetTradeData()
    {
        var tradeData = new List<string>();
        using (var reader = new StreamReader(stream))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                tradeData.Add(line);
            }
        }
        return tradeData;
    }

    private Stream stream;
}

コンストラクターでストリームを通過するのはいつですか?さらに良いことに、GetTradeDataを静的メソッドにして、ストリームをそのメソッドに渡すことは実行可能なオプションでしょうか?保守性と機能性が続く限り、違いは何ですか?これは私にはいつも不明確でした。次のように、プライベートバッキングフィールド+コンストラクターまたは単に静的メソッドをいつ使用するかがわからないようです。

public class StreamTradeDataProvider : ITradeDataProvider
{
    public StreamTradeDataProvider() { }

    public static IEnumerable<string> GetTradeData(Stream stream)
    {
        var tradeData = new List<string>();
        using (var reader = new StreamReader(stream))
        {
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                tradeData.Add(line);
            }
        }
        return tradeData;
    }    
}

前もって感謝します!

4
user3357969

問題は、メソッドを静的にするかどうかではなく、アルゴリズムをステートフルにするかステートレスにするかということだと思います。この場合、静的メソッドから離れたほうがよいと思います。

あなたの例では、インターフェースITradeDataProviderは、静的メソッドではなくインスタンスメソッドの定義を意味します。静的メソッドは継承できないため、継承した場合、これはGetTradeDataメソッドの多態的な設計に影響します。

したがって、より関連性の高い質問は、コンストラクター(ステートフル)またはインスタンスメソッドパラメーター(ステートレス)でコンテキストデータを渡すことのメリットです。

再利用性

考慮すべき1つの側面は、ITradeDataProviderを再利用できるかどうかです。 ITradeDataProviderを、ストリームを処理するためのアルゴリズムを単にカプセル化する戦略パターンと考える場合、特に実際に複数のストリームを一度にまたは特定の頻度で処理する必要がある場合は、このコンテキストの詳細をメソッドで渡す方が理にかなっています。パラメータ。そうすれば、同じストラテジーインスタンスを何度も再利用できます。

_ITradeDataProvider strategy = new DefaultTradeDataProvider();
for(Stream stream : getMyTradeDataStreams()) {
   IEnumerable<string> tradeData = strategy.getTradeData(stream);   
}
_

DefaultTradeDataProviderの複数のインスタンスを作成する意味は、それらすべてが提供されたストリームでアルゴリズムを実行するだけの場合はどうでしょうか。ここでは、1つのインスタンスで十分です。

この場合、ITradeDataProviderの実装はステートレスであり、作業を行うために必要な状態を必ず渡すようにします。

時空コロケーション

ここでのパターンの興味深い側面は、コンテキストデータと戦略アルゴリズムがおそらく時間と空間に配置されていることです。つまり、データのストリームを受け取ったとき、それはおそらくそれを使用するのと同じ場所にあります。

ステートレスとマルチスレッドの利点

ステートレスオブジェクトは一般に再利用性が高く、他のスレッドで実行されている可能性のある他の複数のコンポーネントと共有する場合は、マルチスレッドの問題を心配する必要はありません。

ステートレスオブジェクトを使用すると、アルゴリズムのシングルトンインスタンスを作成して、毎回安全に再利用できる可能性があります。

Statefull Closure

ただし、ステートフルクロージャーを作成する場合、つまり、データと機能をパックし、後で別の時間や別の場所で使用する場合は、状況が少し変わります。

その場合、クロージャー内に状態をパックすると便利な場合があります。

_ITradeDataProvider provider = new DefaultTradeDataProvider(stream);
someOtherService.withProvider(provider);
_

カプセル化

これで、someOtherServiceは、コンテキストの詳細をプロバイダーに渡すことを心配する必要がなくなりました。プロバイダーはすでにそれらの詳細を内部にパックしています。 someServiceは、最初に作成された場所とは異なる場所と時間で使用されます。 someOtherServiceは、到達できない他の場所(つまり、プロバイダーの実装)にカプセル化されているstreamにさえアクセスできない可能性があるため、これは便利です。 someOtherServiceは、データのソースがstreamであるか、それとも別のものであるかを気にしません。それが閉鎖の唯一の責任です。

したがって、これは状態と動作をカプセル化し、他のオブジェクトと共有するための便利な方法である可能性があります。

状態を維持する複雑さ

この場合、責任を持って状態を扱う必要があります。これは、プロバイダーが複数のスレッド間で共有できない可能性があり、スレッドごとにプロバイダーの新しいインスタンスを作成する必要があるか、他のスレッドと安全に共有したい場合は、スレッドセーフにする必要があることを意味します。

元の質問のストリームの例の場合、ストリームを1回消費するとどうなりますか?それでもgetTradeData()を正常に呼び出して、ストリームを再度消費できますか?

したがって、ご覧のとおり、状態のパッキングには、より複雑な影響があります。

4
edalorzo

実際には違いはありません。

最初の例はconstructor injectionと呼ばれます。

2番目の種類は、parametric依存性注入、または単にsageのモデリングと呼ぶものです:AsesB

コンストラクターインジェクションの利点は、受信オブジェクトを最初から有効状態にすることです。

経験則として、オブジェクトが正しく機能するために必要な必要な依存関係オプション依存関係を区別する必要があります。

writerカプセル化された別のdestinationsへの書き込みがあるとします。 writingコンポーネントで初期化する必要があります。これはconstructor injectionを介して行われます。オブジェクトがないと役に立たないでしょう。

ただし、おそらくprocessingステップを実行する可能性が必要なので、このオプションのコンポーネントSetPreProcessorに対してsetter injectionを実行できます。

これはあなたの最初の例をカバーしています。

2番目の例の場合:StreamStreamTradeDataProviderの-​​必須またはオプションコンポーネントではありません。

コンテキストを完全にするには、3番目のオブジェクト(いわゆるmediator)が必要になります。 mediatorStreamStreamTradeDataProviderにアクセスでき、両方を1つにまとめることが仕事です。

コンストラクターでストリームを通過するのはいつですか?

他のコンポーネントから自律コンポーネントを構築したいときはいつでも(理論的には)渡されます(たとえばloggerFileWriterコンポーネントで)。

さらに良いことに、GetTradeDataを静的メソッドにして、ストリームをそのメソッドに渡すことは実行可能なオプションでしょうか?

テスト容易性の観点から非静的メソッドモックするのは簡単です。目的のメソッドを使用して、あらゆる種類のオブジェクトをインスタンス化できます。ここでは静的メソッドの利点はわかりません。

保守性と機能性の点で違いは何ですか?

いつものようにあなたが担当します!コードが実行するとき、それが何をすべきか、そしてコードのテストと作業に問題がない場合(コプログラマーを含む)、あなたは何でも好きなことができます。何も禁じる法律はありません。 copy&pasteの場合でも、地獄に行くつもりはありません。 (ここでは)直接的な利点はありません。異なる(またはより具体的な)状況では、1つある可能性があります。しかし、この例に関する限り、あなたの心があなたに言うことをしてください。

これは私にはいつも不明確でした。プライベートバッキングフィールド+コンストラクターまたは単に静的メソッドをいつ使用するかわからないようです

そして、私の投稿の後でも、特定の不明確さが残っているのではないかと心配しています。

Streambatteryに似ている場合は、それを注入する必要があります。knifeに似ている場合は、両方の方法で実行できます。

constructor injectionの利点は、渡すおもちゃに電池を入れるのを忘れないことだけです。

0
Thomas Junk