プログラミング Scalaを読んでいます。第 4 章の冒頭で、著者は Java が「それほど純粋ではない OO の概念」である静的メソッドをサポートしているとコメントしています。これはなぜですか?
7 に答える
オブジェクト指向とは、次の 3 つのことです。
- メッセージング、
- 状態プロセスのローカル保持と保護と隠蔽、および
- すべてのものの極端な遅延バインディング。
この 3 つのうち、最も重要なのはメッセージです。
静的メソッドは、少なくともメッセージングと遅延バインディングに違反します。
メッセージングの考え方は、オブジェクト指向では、相互にメッセージを送信する自己完結型オブジェクトのネットワークによって計算が実行されることを意味します。メッセージの送信は、通信/計算の唯一の方法です。
静的メソッドはそれを行いません。それらはどのオブジェクトにも関連付けられていません。通常の定義によれば、それらは実際にはメソッドではありません。それらは本当に単なる手順です。Foo.bar
Java の静的メソッドと BASIC サブルーチンの間にほとんど違いはありませんFOO_BAR
。
遅延バインディングに関しては、より現代的な名前はdynamic dispatchです。静的メソッドもこれに違反しています。実際、それはまさにその名前である静的メソッドにもあります。
静的メソッドは、オブジェクト指向の非常に優れた特性を壊します。たとえば、オブジェクト指向システムは、オブジェクトが機能として機能するため、自動的に機能安全です。静的メソッド (または実際には、その静的状態または静的メソッドであるすべての静的) は、そのプロパティを壊します。
オブジェクトはメッセージングを介してのみ通信するため、すべてのオブジェクトを独自のプロセスで並行して実行することもできます。( Actorsと同様に、基本的には、あまり驚くべきことではありません。Carl Hewitt が Smalltalk-71 に基づいて Actor Model を作成し、Alan Kay が部分的に PLANNER に基づいて Smalltalk-71 を作成したためです。これは Carl Hewitt によって作成されました。アクターとオブジェクトの関係は偶然ではなく、実際には本質的に同じものです。) 繰り返しますが、静的 (両方の静的メソッド、特に静的状態) は、その優れた特性を壊します。
「それほど純粋ではない OO の概念」と「悪い習慣」を混同しないでください。「純粋な OO」であることは、達成しようとする万能薬ではありません。静的メソッドがパラメーターとしてインスタンス変数を取らないからといって、それらが役に立たないというわけではありません。オブジェクトには向いていないものもあり、「純粋さ」のためだけに型にはめるべきではありません。
物事は「純粋」であるべきだと考える人もいるため、「不純」なものはすべて悪い習慣です。実際には、悪い習慣とは、紛らわしい、保守しにくい、使いにくいなどのことをしているだけです。インスタンスを取るメソッドはおそらくインスタンス メソッドである必要があるため、インスタンスを取る静的メソッドを作成することは悪い習慣です。一方、ユーティリティやファクトリ関数などは通常、インスタンスを取らないため、静的にする必要があります。
なぜ「純粋なオブジェクト指向」ではないのか疑問に思っているのであれば、それはインスタンス メソッドではないからです。「純粋な」オブジェクト指向言語では、すべてがオブジェクトであり、すべての関数がインスタンス メソッドです。もちろん、それは常に非常に役立つわけではありません。たとえば、Math.atan2
方法を考えてみましょう。2 つの数値が必要で、状態は必要ありません。どのオブジェクトを のメソッドにすることさえできますか? 「純粋な」オブジェクト指向言語では、Math
それ自体がオブジェクト (おそらくシングルトン) でありatan2
、インスタンス メソッドである可能性がありますが、関数は実際にはMath
オブジェクトの状態を使用しないため、「純粋なオブジェクト指向」でもありません。 " 概念。
これまで言及されていなかった静的メソッドがあまりオブジェクト指向ではない理由の 1 つは、インターフェイスと抽象クラスが非静的メソッドのみを定義することです。したがって、静的メソッドは継承にうまく適合しません。
また、静的メソッドは " " にアクセスできないことに注意してくださいsuper
。これは、静的メソッドを実際の意味でオーバーライドできないことを意味します。実際には、それらはまったくオーバーライドできず、非表示になっているだけです。これを試して:
public class Test {
public static int returnValue() {
return 0;
}
public static void main(String[] arg) {
System.out.println(Test.returnValue());
System.out.println(Test2.returnValue());
Test x = new Test2();
System.out.println(x.returnValue());
}
}
public class Test2 extends Test {
public static int returnValue() {
return 1;
}
}
これを実行すると、期待どおりの結果が得られません。 Test.returnValue()
あなたが期待するものを提供します。 スーパークラスで同じ名前のメソッドを非表示にし (オーバーライドしません)、期待どおりの結果が得られます Test2.returnValue()
。
ポリモーフィズムを使用するために静的メソッドを「非静的に」呼び出すことを素朴に期待するかもしれません。そうではありません。変数が宣言されているクラスは、メソッドのルックアップに使用されるクラスです。コードが実際の動作とは異なる動作をすることを誰かが期待する可能性があるため、これは悪い形式です。
これは、「静的メソッドを使用しないでください!」という意味ではありません。シングルトンを作成する怠惰な方法としてだけでなく、Class オブジェクトにメソッドを所有させたいインスタンスに対しては、静的メソッドの使用を予約する必要があることを意味します。
静的メソッドは、オブジェクトが実際に関連付けられていなくても呼び出すことができるため、純粋なオブジェクト指向の概念ではありません。クラス自体を使用します。あなたはこのようにそれらを呼び出しますClassname.method(...);
オブジェクト指向の概念は、オブジェクトからのデータの制御/アクセスに関する話ですが、静的メソッドはオブジェクトを使用して呼び出す必要はなく、オブジェクトではなくクラスに属します。
- 乾杯