静的クラスと静的メンバーの考え方とベストプラクティス[非公開]


11

私は、静的メンバーまたは静的クラス全体に関する考え方と業界のベストプラクティスについて非常に興味があります。これには欠点がありますか、それともアンチパターンに参加していますか?

これらのエンティティは、機能を提供するためにクラスをインスタンス化することを要求または要求しないという意味で、「ユーティリティクラス/メンバー」と見なされます。

これに関する一般的な考えと業界のベストプラクティスは何ですか?

以下のクラスとメンバーの例を参照して、私が参照しているものを説明してください。

// non-static class with static members
//
public class Class1
{
    // ... other non-static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

// static class
//
public static class Class2
{
    // ... other static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

前もって感謝します!



1
@Robert Harvey:あなたが参照した記事は有用ですが、ベストプラクティスや静的クラスを使用する場合の落とし穴についてはあまり説明していません。
バーナード14年

回答:


18

一般的に、静的-特にあらゆる静的状態を避けます。

どうして?

  1. 静力学は並行性の問題を引き起こす。インスタンスは1つしかないため、同時実行間で自然に共有されます。これらの共有リソースは同時プログラミングの悩みの種であり、多くの場合、共有する必要ありません。

  2. 静電気は単体テストで問題を引き起こします。ソルトに値する単体テストフレームワークは、テストを同時に実行します。次に、#1に遭遇します。さらに悪いことに、すべてのセットアップ/分解のテストと、セットアップコードを「共有」しようとするハッカーがテストを複雑にします。

小さなものもたくさんあります。静力学は柔軟性に欠ける傾向があります。それらをインターフェースしたり、オーバーライドしたり、構築のタイミングを制御したり、ジェネリックでうまく使用したりすることはできません。本当にバージョン管理することはできません。

確かに静的変数の使用があります:定数値は素晴らしい働きをします。ここでは、単一のクラスに収まらない純粋なメソッドがうまく機能します。

しかし、一般的にはそれらを避けてください。


私はあなたが意味する並行性が不可能な程度に興味があります。それを拡張できますか?メンバーが分離なしでアクセスできることを意味する場合、それは完全に理にかなっています。静的変数のユースケースは、私が通常使用するものです:定数値と純粋/ユーティリティメソッド。それが最高であり、静的の99%のユースケースであれば、それは私にある程度の快適さを与えます。また、あなたの答えのために+1。素晴らしい情報。
トーマスストリンガー14年

@ThomasStringer-スレッド/タスク間のタッチポイントが増えると、同時実行の問題が発生する可能性が高くなり、同期を行うことでパフォーマンスが低下する可能性が高くなります。
テラスティン14年

あるスレッドが現在静的メンバーにアクセスしている場合、他のスレッドは所有スレッドがリソースを解放するまで待つ必要がありますか?
トーマスストリンガー14年

@ThomasStringer-たぶん、そうでないかもしれない。この点で、Staticsは(ほとんど、ほとんどの言語で)他の共有リソースと変わりません。
Telastyn 14年

@ThomasStringer:残念ながら、メンバーをマークしない限り、実際にはこれよりも悪いですvolatile。揮発性データのないメモリモデルからは保証されないため、1つのスレッドで変数を変更しても、すぐに反映されない場合やまったく反映されない場合があります。
Phoshi

17

機能が「純粋」である場合、問題はありません。純粋な関数は入力パラメーターでのみ動作し、それに基づいて結果を提供します。グローバルな状態や外部コンテキストには依存しません。

独自のコード例を見ると:

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
}

静的(拡張)関数を使用すると、コードの最初の部分がはるかに読みやすくなり、読みやすさが非常に重要になるため、必要に応じて静的関数を使用します。

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