J'ai les cours suivants
class Person {
private String name;
void getName(){...}}
class Student extends Person{
String class;
void getClass(){...}
}
class Teacher extends Person{
String experience;
void getExperience(){...}
}
Ceci est juste une version simplifiée de mon schéma actuel. Au départ, je ne connais pas le type de personne à créer. La fonction qui gère la création de ces objets prend alors l'objet général Person
en tant que paramètre.
void calculate(Person p){...}
Maintenant, je veux accéder aux méthodes des classes enfant en utilisant cet objet de classe parent. J'ai aussi besoin d'accéder de temps en temps aux méthodes de classe parentes pour que JE NE POUVAIS PAS LE FAIRE EN RÉSUMER .
Je suppose que j'ai trop simplifié dans l'exemple ci-dessus, alors voici la structure actuelle.
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())
{...}
}
}
La déclaration if indique "impossible de trouver getMultiple pour QuestionOption". OuestionOption a beaucoup plus de classes enfants qui ont différents types de méthodes qui ne sont pas communes chez les enfants (getMultiple n'est pas commun chez les enfants)
NOTE:Bien que cela soit possible, ce n'est pas du tout recommandé car cela détruit en quelque sorte la raison de l'héritage. Le meilleur moyen serait de restructurer la conception de votre application de manière à ce qu'il existe des dépendancesNOparent à enfant. Un parent ne devrait jamais avoir besoin de connaître ses enfants ou leurs capacités.
Cependant .. vous devriez pouvoir le faire comme:
void calculate(Person p) {
((Student)p).method();
}
un moyen sûr serait:
void calculate(Person p) {
if(p instanceof Student) ((Student)p).method();
}
Une classe de parents ne devrait pas connaître les classes d'enfants. Vous pouvez implémenter une méthode calculate()
et la remplacer dans chaque sous-classe:
class Person {
String name;
void getName(){...}
void calculate();
}
et alors
class Student extends Person{
String class;
void getClass(){...}
@Override
void calculate() {
// do something with a Student
}
}
et
class Teacher extends Person{
String experience;
void getExperience(){...}
@Override
void calculate() {
// do something with a Student
}
}
Au fait. Votre déclaration concernant les classes abstraites est source de confusion. Vous pouvez appeler des méthodes définies dans une classe abstraite, mais bien sûr uniquement d'instances de sous-classes.
Dans votre exemple, vous pouvez créer Person
abstract et utiliser getName()
sur instanced of Student
et Teacher
.
Beaucoup des réponses suggèrent de mettre en œuvre des types de variantes utilisant "Décomposition classique orientée objet". Autrement dit, tout ce qui pourrait être nécessaire sur l'une des variantes doit être déclaré à la base de la hiérarchie. Je soutiens que cette approche est digne de ce nom, mais souvent très mauvaise. Vous finissez par exposer toutes les propriétés internes de toutes les variantes (la plupart d'entre elles sont "non valides" pour chaque variante particulière) ou vous encombrez l'API de la hiérarchie avec des tonnes de méthodes procédurales une nouvelle procédure est imaginée).
J'hésite à le faire, mais voici un plug éhonté pour un article de blog que j'ai écrit qui décrit environ 8 façons de créer des types de variantes en Java. Ils craignent tous, parce que Java craint les variantes. Jusqu'à présent, le seul langage JVM qui fonctionne correctement est Scala.
http://jazzjuice.blogspot.com/2010/10/6-things-i-hate-about-Java-or-scala-is.html
Les créateurs de Scala ont en fait écrit un article sur trois des huit méthodes. Si je peux le localiser, je mettrai à jour cette réponse avec un lien.
UPDATE: l'a trouvé ici .
Pourquoi n'écrivez-vous pas simplement une méthode vide dans Person et ne la remplacez pas dans les classes enfants? Et appelez-le, quand il le faut:
void caluculate(Person p){
p.dotheCalculate();
}
Cela voudrait dire que vous devriez avoir la même méthode dans les deux classes, mais je ne vois pas pourquoi cela poserait un problème.
J'ai eu la même situation et j'ai trouvé un moyen de contourner avec un peu d'ingénierie comme suit - -
Vous devez avoir votre méthode dans la classe parente sans aucun paramètre et utiliser - -
Class<? extends Person> cl = this.getClass(); // inside parent class
Maintenant, avec 'cl', vous pouvez accéder à tous les champs de classe enfant avec leur nom et leurs valeurs initialisées en utilisant - -
cl.getDeclaredFields(); cl.getField("myfield"); // and many more
Dans cette situation, votre pointeur 'this' référencera votre objet de classe enfant si vous appelez une méthode parent via votre objet de classe enfant.
Object obj = cl.newInstance () est également nécessaire.
Faites-moi savoir si vous êtes toujours coincé quelque part.
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();
}
}
Une solution possible peut être
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......
}
}
}