21

私は次のクラスを持っています

class Person {
    private String name;
    void getName(){...}}

class Student extends Person{
    String class;
    void getClass(){...}
}

class Teacher extends Person{
    String experience;
    void getExperience(){...}
}

これは私の実際のスキーマの単純化されたバージョンです。最初は、作成する必要のある人物のタイプがわからないため、これらのオブジェクトの作成を処理する関数は、一般的なPersonオブジェクトをパラメーターとして受け取ります。

void calculate(Person p){...}

次に、この親クラスオブジェクトを使用して子クラスのメソッドにアクセスします。また、親クラスのメソッドに時々アクセスする必要があるため、抽象化できません


上記の例では単純化しすぎたと思いますので、これが実際の構造です。

class Question {
  // private attributes
  :
  private QuestionOption option;
  // getters and setters for private attributes
  :
  public QuestionOption getOption(){...}
 }

 class QuestionOption{
 ....
 }
 class ChoiceQuestionOption extends QuestionOption{
 private boolean allowMultiple;
 public boolean getMultiple(){...}
 }

 class Survey{
  void renderSurvey(Question q) {
      /*
          Depending on the type of question (choice, dropdwn or other, I have to render
          the question on the UI. The class that calls this doesnt have compile time 
          knowledge of the type of question that is going to be rendered. Each question 
          type has its own rendering function. If this is for choice , I need to access 
          its functions using q. 
      */
      if(q.getOption().getMultiple())
        {...}
  }
 }

ifステートメントは「QuestionOptionのgetMultipleが見つかりません」と言っています。OuestionOptionには、子間で一般的ではないさまざまなタイプのメソッドを持つ子クラスがさらに多くあります(getMultipleは子間で一般的ではありません)

4

7 に答える 7

39

注:これは可能ですが、継承の理由を破壊するようなものであるため、まったくお勧めしません。最善の方法は、親から子への依存関係がないようにアプリケーション設計を再構築することです。親は自分の子供やその能力を知る必要はありません。

しかし..あなたはそれを次のように行うことができるはずです:

void calculate(Person p) {
    ((Student)p).method();
}

安全な方法は次のとおりです。

void calculate(Person p) {
    if(p instanceof Student) ((Student)p).method();
}
于 2012-07-13T08:05:23.970 に答える
11

親クラスは子クラスの知識を持ってはなりません。メソッドを実装しcalculate()て、すべてのサブクラスでオーバーライドできます。

class Person {
    String name;
    void getName(){...}
    void calculate();
}

その後

class Student extends Person{
    String class;
    void getClass(){...}

    @Override
    void calculate() {
        // do something with a Student
    }
}

class Teacher extends Person{
    String experience;
    void getExperience(){...}

    @Override
    void calculate() {
        // do something with a Teacher
    }

}

ところで。抽象クラスについてのあなたの発言は紛らわしいです。抽象クラスで定義されたメソッドを呼び出すことができますが、もちろんサブクラスのインスタンスのみです。

あなたの例では、Person抽象化して、getName()インスタンス化されたStudentとの使用を行うことができますTeacher

于 2012-07-13T08:26:06.973 に答える
3

ここでの回答の多くは、「古典的なオブジェクト指向の分解」を使用してバリアント型を実装することを提案しています。つまり、バリアントの1つで必要になる可能性のあるものはすべて、階層のベースで宣言する必要があります。私は、これはタイプセーフですが、多くの場合非常に悪いアプローチであることを提出します。すべての異なるバリアントのすべての内部プロパティを公開することになります(そのほとんどは特定のバリアントごとに「無効」です)、または階層のAPIを大量の手続き型メソッドで乱雑にすることになります(つまり、毎回再コンパイルする必要があります)新しい手順が夢見られています)。

私はこれを行うことを躊躇しますが、これは私が書いたブログ投稿の恥知らずなプラグであり、Javaでバリアント型を実行する8つの方法の概要を示しています。Javaはバリアント型を吸うので、それらはすべて吸う。これまでのところ、それを正しく行う唯一のJVM言語はScalaです。

http://jazzjuice.blogspot.com/2010/10/6-things-i-hate-about-java-or-scala-is.html

Scalaの作成者は、実際には8つの方法のうち3つについて論文を書きました。追跡できれば、この回答をリンクで更新します。

更新ここで見つかりました。

于 2012-07-13T08:09:26.443 に答える
2

Personで空のメソッドを記述し、それを子クラスでオーバーライドしてみませんか?そして、それが必要なときにそれを呼び出します:

void caluculate(Person p){
  p.dotheCalculate();
}

これは、両方の子クラスで同じメソッドを使用する必要があることを意味しますが、なぜこれが問題になるのかはわかりません。

于 2012-07-13T08:22:08.907 に答える
2

私も同じ状況で、次のように少しエンジニアリングを行う方法を見つけました---

  1. パラメータを指定せずに親クラスにメソッドを設定し、--を使用する必要があります。

    Class<? extends Person> cl = this.getClass(); // inside parent class
    
  2. これで、「cl」を使用して、名前と初期化された値を使用して、すべての子クラスフィールドにアクセスできます。

    cl.getDeclaredFields(); cl.getField("myfield"); // and many more
    
  3. この状況で、子クラスオブジェクトを介して親メソッドを呼び出す場合、「this」ポインタは子クラスオブジェクトを参照します。

  4. 使用する必要があるかもしれないもう1つのことは、Object obj = cl.newInstance();です。

それでもどこかで行き詰まったら教えてください。

于 2015-02-20T06:56:37.077 に答える
1
class Car extends Vehicle {
        protected int numberOfSeats = 1;

        public int getNumberOfSeats() {
            return this.numberOfSeats;

        }

        public void  printNumberOfSeats() {
          //  return this.numberOfSeats;
            System.out.println(numberOfSeats);
        }


    } 

//Parent class

  class Vehicle {
        protected String licensePlate = null;

        public void setLicensePlate(String license) {
            this.licensePlate = license;
            System.out.println(licensePlate);
        }


   public static void main(String []args) {
       Vehicle c = new Vehicle();

      c.setLicensePlate("LASKF12341"); 

//Used downcasting to call the child method from the parent class. 
//Downcasting = It’s the casting from a superclass to a subclass.

      Vehicle d = new Car();
      ((Car) d).printNumberOfSeats();


   }
   }
于 2018-10-04T09:25:55.677 に答える
0

考えられる解決策の1つは

class Survey{
  void renderSurvey(Question q) {
  /*
      Depending on the type of question (choice, dropdwn or other, I have to render
      the question on the UI. The class that calls this doesnt have compile time 
      knowledge of the type of question that is going to be rendered. Each question 
      type has its own rendering function. If this is for choice , I need to access 
      its functions using q. 
  */
  if(q.getOption() instanceof ChoiceQuestionOption)
  {
    ChoiceQuestionOption choiceQuestion = (ChoiceQuestionOption)q.getOption();
    boolean result = choiceQuestion.getMultiple();
    //do something with result......
  }
 }
}
于 2012-07-16T11:12:11.137 に答える