1. ホーム
  2. c#

[解決済み] C#で静的クラスを使用する場合【重複】について

2022-03-15 09:02:13

質問

以下は、その内容です。 MSDNは、以下のように言っています。 静的クラスを使用する場合 :

static class CompanyInfo
{
    public static string GetCompanyName() { return "CompanyName"; }
    public static string GetCompanyAddress() { return "CompanyAddress"; }
    //...
}

の単位として静的クラスを使用します。 メソッドで構成されます。 特定のオブジェクトに関連付けられます。 また、静的クラスは 実装をよりシンプルに、より高速に を作成する必要がないため オブジェクトのメソッドを呼び出すことができます。 メソッドを整理しておくと便利です。 クラス内部で意味のある方法で 例えば、Mathクラスのメソッド をSystemネームスペースで使用します。

私には、この例は静的クラスの使用シナリオをあまりカバーしていないように思えます。過去に私は、関連する関数のステートレスなスイートに静的クラスを使用したことがありますが、それくらいです。では、どのような状況でクラスを静的に宣言すべきなのでしょうか?

どのように解決するのか?

静的クラスについては、以前のStack Overflowの回答で私の考えを書きました。 単一のメソッドを持つクラス -- 最適なアプローチ?

私は以前、静的メソッドで満たされたユーティリティクラスが大好きでした。そうしなければ冗長性とメンテナンス地獄を引き起こしてしまうようなヘルパーメソッドを、見事に統合してくれたのです。インスタンス化することもなく、廃棄することもなく、ただ火をつけるだけで、とても簡単に使うことができます。これは、私がサービス指向アーキテクチャを作ろうとした最初の無意識の試みだったと思います。しかし、システムが成長するにつれて、ドラゴンがやってくるようになりました。

ポリモーフィズム

例えば、UtilityClass.SomeMethodというメソッドがあり、楽しげに動作しているとします。突然、その機能を少し変更する必要が出てきました。ほとんどの機能は同じですが、それでもいくつかの部分を変更する必要があります。もしこれが静的メソッドでなかったら、派生クラスを作って必要に応じてメソッドの内容を変更することができます。スタティック・メソッドである以上、それはできない。確かに、古いメソッドの前後に機能を追加するだけなら、新しいクラスを作成して、その中で古いメソッドを呼び出せばよいのですが、それは単に気持ち悪いだけです。

インターフェイスの悩み

静的メソッドは、論理的な理由からインターフェースを通して定義することができません。また、静的メソッドをオーバーライドできないので、静的クラスをインターフェースで受け渡しする必要がある場合、静的クラスは役に立ちません。このため、strategyパターンの一部として静的クラスを使用することはできません。この問題を解決するために インターフェースの代わりにデリゲートを渡す .

テスト

これは基本的に、上記のインターフェイスの問題と密接に関係しています。実装を交換する能力は非常に限られているので、プロダクションコードをテストコードに置き換えることも困難です。繰り返しになりますが、ラップすることは可能ですが、実際のオブジェクトの代わりにラッパーを受け入れることができるようにするために、コードの大部分を変更する必要があります。

ブロブ(塊)の育成

静的メソッドは通常ユーティリティメソッドとして使われ、ユーティリティメソッドは通常異なる目的を持つので、すぐにまとまりのない機能で満たされた大きなクラスになってしまいます。理想的には、各クラスはシステム内で単一の目的を持つべきです。目的がきちんと定義されているのであれば、むしろ5倍くらいのクラスがあってもいいと思います。

パラメータクリープ

そもそも、その小さなかわいくて無邪気な静的メソッドは、1つのパラメータを取るかもしれません。機能が大きくなるにつれて、新しいパラメータがいくつか追加されます。やがて、さらにオプションのパラメータが追加されるので、メソッドのオーバーロードを作成します(または、それをサポートする言語ではデフォルト値を追加するだけです)。やがて、10個のパラメータを受け取るメソッドができあがります。本当に必要なのは最初の3つだけで、4から7はオプションである。しかし、パラメータ6を指定すると、7-9も入力する必要がある...。この静的メソッドと同じことをするためだけにクラスを作るのであれば、コンストラクタで必要なパラメータを取り込み、ユーザーがプロパティやメソッドで任意の値を設定し、相互に依存する複数の値を同時に設定することで解決できるはずなのです。また、これだけ複雑なメソッドになると、いずれにせよ独自のクラスにする必要がある場合がほとんどです。

理由もなくクラスのインスタンスを作成するようコンシューマに要求すること

よくある議論のひとつに なぜ、このクラスの消費者に、このメソッドを呼び出すためにインスタンスを生成することを要求し、その後にインスタンスを使用することはないのでしょうか?クラスのインスタンスを生成するのは、ほとんどの言語において非常に安価な処理なので、スピードは問題ではありません。コンシューマに一行のコードを追加することは、将来的により保守性の高いソリューションの基礎を築くための低コストと言えます。最後に、インスタンスの作成を避けたい場合は、クラスのシングルトンラッパーを作成すれば、簡単に再利用することができます。ただし、この場合、クラスがステートレスであることが条件となります。もしステートレスでない場合でも、静的なラッパーメソッドを作成することで、すべてを処理することができ、長期的にはすべての利点を得ることができます。最後に、シングルトンであるかのようにインスタンス化を隠すクラスを作ることもできます。MyWrapper.Instance]は、プロパティとして、単に[MyWrapper.Instance]を返します。 new MyClass();

シスだけが絶対的なものを扱える

もちろん、私がスタティック・メソッドを嫌うのには例外があります。肥大化の心配がない真のユーティリティクラスは、静的メソッドの優れたケースです。例えば、System.Convert。もし、あなたのプロジェクトが、将来のメンテナンスの必要がない一過性のものであれば、全体のアーキテクチャはあまり重要ではありません。

標準、標準、標準!

インスタンスメソッドを使うことは、スタティックメソッドを使うことを阻害するものではありませんし、その逆もまた然りです。差別化の背後に理由があり、それが標準化されている限りはね。ビジネスレイヤーに様々な実装方法が散らばっているのを見るのは、何にもまして嫌なものです。