3

ですから、かなり基本的な質問があると思います。プロジェクト com.bee.buzz に含める com.cow.moo というオープン ソース Java プログラムがあるとします。

moo にはすばらしいクラスがたくさんありますが、そのほとんどは触りたくありませんが、触るクラスがいくつかあります。この時点で、変更したいクラスを拡張するのが最善の方法ですよね? (拡張と実装については多くのことが言われてきましたが、これらのクラスはどれもインターフェイスではないので、それはちょっと問題外です。)

私の質問は、これが moo のクラスだとします。

package com.cow.moo;
public class Milk {
    private float currentMilk;
    public int getMilk() { /* Stuff */ }
    public float convertToGallons (float liquid) { /* More Stuff */ }
}

ここで、Milk を拡張する新しいクラスで getMilk を使用したいとします。ただし、Milk の getMilk は、プライベート変数 (currentMilk など) と、含めない他の関数 (convertToGallons など) に依存しています。新しい関数を正しく動作させたい場合、これらの他の変数と関数を含める必要がありますか? 関数を大幅に変更したくはありません。少し追加するだけです。これを行う最善の方法は何ですか?

大規模なプロジェクトを構築する際の一般的なヒントも役立ちます。ここにいる Java 専門家の何人かが答えを出すのに 5 秒もかからないと思います。御時間ありがとうございます。

4

5 に答える 5

6

一般的な推奨事項は、継承よりも構成を優先することです。

たとえば、次のように、ニーズにほぼ適合するインターフェイスと既存の実装があります。

public interface MilkProvider { public float getMilk(); }
public class Milk implements MilkProvider { // same as you example }

別のカスタム実装が必要な場合は、次のようにコーディングできます。

public class MyMilk implements MilkProvider {
  private MilkProvider milk; 

  public MyMilk(int someValue) {
    milk = new Milk(someValue);  // unfortunatly we can't get rid of a depencency
                                 // to the concrete class because we need to create
                                 // something. An existing factory could help, but
                                 // but usually there's none implemented.
  }

  public float getMilk() {
    float result = milk.getMilk();
    // do somethink with the result
    return float;
  }
}
于 2010-08-12T07:35:55.657 に答える
1

この場合、より良い解決策はポリモーフィズム(静的ポリモーフィズム)であるか、リフレクションを使用して(この方法は使用しないでください)プライベート変数に到達できると思います。

于 2010-08-12T07:32:33.920 に答える
1

ここで、Milk を拡張する新しいクラスで getMilk を使用したいとします。ただし、Milk の getMilk は、プライベート変数 (currentMilk など) と、含めない他の関数 (convertToGallons など) に依存しています。新しい関数を正しく動作させたい場合、これらの他の変数と関数を含める必要がありますか?

パブリック関数と変数を含める必要はありません。継承の中心的な概念は、サブクラスとして、サブクラスに含まれる親クラスのすべてのパブリック (および保護された) メンバーを無料で取得することです。したがって、サブクラス (たとえば、HoneyMilk としましょう) は最初convertToGallonsからすぐに呼び出すことができます。

この場合のオーバーライドgetMilkは、(サブクラスがアクセスできない) プライベート変数に依存しているため、かなりトリッキーです。私のアドバイスは、クラスを「ホワイト ボックス」として扱うのではなく、「ブラック ボックス」として扱う考え方を変えることです。getMilkつまり、Milk のソース コードを実際に見ることができないかのように、オーバーライドされたバージョンの を実装する必要があります。回り道の解決策のように思えるかもしれませんが (つまり、ここでこの行を微調整できないのはなぜですか?!)、親クラスが公開しているものだけを使用してサブクラスを実装する必要があります。また、大規模なプロジェクトを開発する際に利用することが絶対に不可欠な抽象化の重要性も強調しています。

于 2010-08-12T07:48:20.760 に答える
0

クラスを拡張し、インスタンス変数がパブリックである場合は、メソッドアクセサー(ゲッターとセッター)を介してインスタンス変数にアクセスできます。

AOP(アスペクト指向プログラミング)を使用すると、ソースを変更せずに、実行時にmooクラスを変更できます。

いくつかの構成と継承のトピックも読むことを検討してください。

これがお役に立てば幸いです。

于 2010-08-12T07:34:54.453 に答える
0

ちょっと醜いJavaリフレクションを使わない限り、プライベートクラスのメンバーを使うことはできません。私があなたである場合(そして変更がそれほど重くない場合は、元のプロジェクトをフォークします)、実行時にコードを変更するか、アスペクトウィービング(アスペクト指向プログラミング)を使用して静的に変更することを検討します。AspectJは、鋭い学習曲線を持っているように見えるかもしれませんが、ツールボックスに含めるのに最適なツールであり、ここでのニーズに完全に一致します。

于 2010-08-12T07:36:55.513 に答える