機能が「純粋」である場合、問題はありません。純粋な関数は入力パラメーターでのみ動作し、それに基づいて結果を提供します。グローバルな状態や外部コンテキストには依存しません。
独自のコード例を見ると:
public class Class1
{
public static string GetSomeString()
{
// do something
}
}
この関数はパラメーターを取りません。したがって、おそらく純粋ではありません(この関数の純粋な実装は、定数を返すことだけです)。この例は実際の問題を代表するものではないと思いますが、これはおそらく純粋な機能ではないことを指摘しているだけです。
別の例を見てみましょう。
public static bool IsOdd(int number) { return (number % 2) == 1; }
この関数が静的であることに問題はありません。これを拡張機能にして、クライアントコードをさらに読みやすくすることもできます。拡張関数は、基本的には特別な種類の静的関数です。
Telastynは、静的メンバーの潜在的な問題として並行性を正しく言及しています。ただし、この関数は共有状態を使用しないため、ここでは同時実行性の問題はありません。数千のスレッドが、同時実行性の問題なしにこの関数を同時に呼び出すことができます。
.NETフレームワークでは、拡張メソッドがかなり以前から存在していました。LINQには多くの拡張関数が含まれています(たとえば、Enumerable.Where()、Enumerable.First()、Enumerable.Single()など)。これらは悪くないと思いますか?
コードで置換可能な抽象化を使用すると、ユニットテストで多くの場合にメリットが得られ、ユニットテストでシステムコードをテストダブルに置き換えることができます。静的関数はこの柔軟性を妨げますが、これは、たとえば実際のデータアクセスレイヤーを偽のデータアクセスレイヤーに置き換えるアーキテクチャレイヤーの境界で最も重要です。
ただし、ある数が奇数か偶数かに応じて異なる動作をするオブジェクトのテストを作成する場合、IsOdd()
関数を別の実装に置き換える必要はありません。同様に、Enumerable.Where()
テストの目的で別の実装を提供する必要がある場合もわかりません。
この関数のクライアントコードの可読性を調べてみましょう。
オプションa(機能が拡張メソッドとして宣言されている場合):
public void Execute(int number) {
if (number.IsOdd())
// Do something
}
オプションb:
public void Execute(int number) {
var helper = new NumberHelper();
if (helper.IsOdd(number))
// Do something
}
静的(拡張)関数を使用すると、コードの最初の部分がはるかに読みやすくなり、読みやすさが非常に重要になるため、必要に応じて静的関数を使用します。