私は Java (および OOP) を学んでおり、現在の状況とは無関係かもしれませんが、SO が一般的な落とし穴や優れた設計プラクティスを共有できるかどうか疑問に思っていました。
13 に答える
覚えておくべき重要なことの 1 つは、静的メソッドはサブクラスによってオーバーライドできないということです。コード内の静的メソッドへの参照は、本質的にそれをその実装に結び付けます。インスタンス メソッドを使用する場合、インスタンスの型に基づいて動作を変えることができます。ポリモーフィズムを利用できます。静的メソッドは、動作が固定されている実用的なタイプの操作により適しています。たとえば、base 64 エンコーディングやチェックサムの計算などです。
いずれの答えも、いつどちらを選択するかというOOの理由の核心に到達するとは思いません。もちろん、インスタンス メンバーを処理する必要がある場合はインスタンス メソッドを使用しますが、すべてのメンバーをパブリックにしてから、クラスのインスタンスを引数として受け取る静的メソッドをコーディングすることもできます。こんにちはC。
設計しているオブジェクトが応答するメッセージについて考える必要があります。これらは常にインスタンス メソッドになります。オブジェクトをこのように考えると、静的メソッドを持つことはほとんどありません。特定の状況では、静的メンバーは問題ありません。
注目すべき例外として、Factory Method と Singleton (控えめに使用) パターンがあります。「ヘルパー」クラスを書きたくなる場合は注意してください。そこから手続き型プログラミングへの滑りやすい坂道になるからです。
メソッドの実装がクラスの public インターフェイス (ダウンキャストなし) で完全に表現できる場合、それは静的な「ユーティリティ」メソッドの良い候補となる可能性があります。これにより、最小限のインターフェイスを維持しながら、コードのクライアントが頻繁に使用する便利なメソッドを提供できます。Scott Meyers が説明しているように、このアプローチは、クラスの内部実装への変更によって影響を受けるコードの量を最小限に抑えることにより、カプセル化を促進します。Herb Sutter による別の興味深い記事では、std::basic_string を分解して、どのメソッドをメンバーにする必要があり、どのメソッドをメンバーにするべきではないかを判断しています。
Java や C++ のような言語では、静的メソッドによってコードが洗練されていないため、まだトレードオフがあることは認めます。C# では、拡張メソッドによって両方の長所を活用できます。
何らかの理由で操作をサブクラスでオーバーライドする必要がある場合は、もちろんインスタンス メソッドである必要があります。その場合、継承用のクラスを設計するためのすべての要因を考慮する必要があります。
私の経験則は、クラス インスタンス変数を使用する必要があるかどうかに関係なく、メソッドがクラスの特定のインスタンスに関連する何かを実行する場合です。必ずしもクラスのインスタンスを参照せずに特定のメソッドを使用する必要がある状況を考えることができる場合、そのメソッドは間違いなく静的 (クラス) である必要があります。特定のケースでこのメソッドもインスタンス変数を使用する必要がある場合は、静的メソッドを呼び出してインスタンス変数を渡す別のインスタンス メソッドを作成するのがおそらく最善です。パフォーマンスに関しては、ごくわずかな違いがあると思います (少なくとも .NET では、Java では非常に似ていると思いますが)。
オブジェクトの状態 (値) を保持し、メソッドを使用して状態にアクセスまたは変更する場合は、インスタンス メソッドを使用する必要があります。
メソッドが状態を変更しない場合でも (ユーティリティ関数)、インスタンス メソッドを使用することをお勧めします。主な理由は、この方法で別のアクションを実行するサブクラスを作成できるためです。
残りについては、静的メソッドを使用できます。
:)
私の静的メソッドは常に次のいずれかです。
- そのクラスにのみ役立つ式を評価するプライベート「ヘルパー」メソッド。
- ファクトリメソッド(
Foo.getInstance()
など) - 最終的な「ユーティリティ」クラスでは、プライベートコンストラクターがあり、パブリック静的メソッド以外は何も含まれていません(例
com.google.common.collect.Maps
) 。
インスタンス変数を参照していないという理由だけで、メソッドを静的にすることはしません。
私見、それを静的メソッドにすることができる場合(構造を変更する必要なしに)、静的メソッドにします。それはより速く、より簡単です。
メソッドをオーバーライドしたいことがわかっている場合は、実際にこれを行う単体テストを作成することをお勧めします。そのため、静的にすることはもはや適切ではありません。それが大変な作業のように聞こえる場合は、インスタンス メソッドにしないでください。
一般的に、ある日の使用を想像してすぐに機能を追加するべきではありません (その方法は狂気の嘘です)。実際に必要であることがわかっている機能のみを追加する必要があります。
より長い説明のために...
基本的に、経験則は、オブジェクト、インスタンスに固有のデータを使用するかどうかです。したがって、Math.max は静的ですが、BigInteger.bitCount() はインスタンスです。ドメイン モデルがそうであるように明らかに複雑になり、境界線上のケースもありますが、一般的な考え方は単純です。
このスレッドは関連しているように見えます:メソッドは静的にすることができますが、そうすべきですか? C# と Java の違いは、その関連性に影響を与えません (私は思います)。
デフォルトではインスタンス メソッドを使用します。利点は、サブクラスで動作をオーバーライドできること、またはインターフェイスに対してコーディングしている場合は、コラボレーターの代替実装を使用できることです。これは、コードをテストする際の柔軟性に非常に役立ちます。
静的参照は実装に組み込まれており、変更できません。static は短いユーティリティ メソッドに役立つと思います。静的メソッドの内容が非常に大きい場合は、責任を 1 つ以上の個別のオブジェクトに分割し、それらをオブジェクト インスタンスとしてクライアント コードと連携させることを検討してください。
デフォルトで選択するのはインスタンス メソッドです。
静的メソッドの問題は、実装に結合されているため、コア オブジェクト指向の原則の 1 つを破っていることです。オープン クローズの原則をサポートし、(動作の抽象的な意味で) 依存関係を記述するインターフェイスをクラスに実装させ、クラスをそのインターフェイスに依存させたいと考えています。その時点以降は、より簡単に拡張できます。..
インスタンス変数を使用する場合は、インスタンス メソッドである必要があります。
そうでない場合、それはあなた次第ですが、多くの静的メソッドや静的な非最終変数があることに気付いた場合は、おそらくすべての静的なものを新しいクラスインスタンスに抽出したいと思うでしょう。(一連の静的メソッドとメンバーはシングルトンですが、本当に厄介なものです。実際のシングルトン オブジェクトを使用する方が良いでしょう。たまたまそのうちの 1 つが存在する通常のオブジェクトが最適です!)。