2017-05-30 1 views
1

J'essaie d'en apprendre davantage sur la classe Interface et Abstract et ses utilisations. Par exemple, j'ai un Interface IPlan. Avoir trois classes l'implémentant, schoolPlan, highSchoolPlan, collegePlan. Si je veux écrire une méthode de service createPlan() qui acceptera l'un de ces trois objets de type plan, comment le faire? Dans ma classe de service, si je fais quelque chose comme,Utilisation de la classe Interface and Abstract

public String createPlan(IPlan plan) {} 

Comme l'objet passé sera instancié comme iPLAN, et je ne serai pas en mesure d'accéder aux variables des objets que je veux créer. Alors, dois-je apporter en classe abstraite, comme

public String createPlan(AbstractPlan plan) {} 

Ou est-ce modèle tout à fait tort?

+1

pouvez-vous montrer un exemple des variables auxquelles vous voulez accéder et de ce que vous avez l'intention de les utiliser? –

+1

Oui, vous devez utiliser la classe abstraite dans le cas où vous avez plusieurs propriétés partagées et que vous souhaitez implémenter une méthode sur toutes ces classes. –

+2

Qu'est-ce que 'createPlan' est censé faire? Il renvoie un 'String'? Quelque chose appelé "createXXX' devrait, par convention, retourner un' XXX'. –

Répondre

2

S'il y a des variables d'instance qui existeront dans tous les IPlan, peu importe quel genre de IPlan il est, alors il est approprié d'avoir une classe abstract qui définit les variables. En fait, vous pourriez envisager de définir uniquement la classe abstraite, et non l'interface. Si la seule utilisation de l'interface est d'avoir une classe abstraite l'implémentant, avec tout le reste étant une sous-classe de la classe abstraite, l'interface ne sert pas à grand chose.

Si les variables sont différentes pour les différents types de IPlan s, alors createPlan ne devrait pas tenter d'accéder aux variables. C'est une erreur débutant commune d'écrire du code comme

public String createPlan(AbstractPlan plan) { 
    ... 
    if (plan instanceof SchoolPlan) { 
     return doSomethingWith(((SchoolPlan)plan).schoolType, ...) 
    } else if (plan instanceof HighSchoolPlan) { 
     return doSomethingElseWith(((HighSchoolPlan)plan).schedule, ...) 
    ... 
} 

Cela annule le but du polymorphisme. Au lieu de cela, vous voudriez demander: quelles parties de createPlan sont communes entre toutes les classes, et quelles choses vont être différentes entre les différentes sous-classes? Les choses qui sont différentes peuvent être transformées en méthodes que vous définiriez dans la classe abstract (idéalement, si votre "classe de service" se trouve dans le même paquet, vous devrez en faire protected méthodes pour que createPlan puisse les utiliser mais elles ne le feraient pas. ne sera pas utilisable partout ailleurs). Par exemple, si la chaîne renvoyée par createPlan contient un titre qui inclut la description du plan, mais que la description dépend de différentes variables propres à chaque type de plan, vous pouvez définir une méthode abstraite getDescription() que vous implémenteriez dans chaque classe.

[Je ne dis pas que instanceof est toujours mauvais; mais les cas où cela est vraiment nécessaire sont relativement rares, et généralement vous devriez chercher une alternative.]

P.S. L'utilisation de I pour indiquer qu'une interface est une convention C# que les programmeurs Java ont tendance à utiliser.

0

Dans l'interface, vous ne pouvez pas implémenter vos méthodes ici, il suffit de les définir. Selon votre exemple, nous allons essayer de faire comme ci-dessous:

interface IPlan { 
    String createPlan(); 
} 

public abstract class APlan implements IPlan { 
    @Override 
    String createPlan() { 
     //do something in general for schoolplan, collegeplan, highschoolplan. 
    } 
} 

public class SchoolPlan extends APlan { 
    @Override 
    String createPlan() { 
     super(); 
     //do something unique for school plan here. 
    } 
} 

Vous pouvez également ne pas utiliser des tableaux polymorphes si vous utilisez l'approche d'interface - mais seulement si vous faites vos classes héritent.