2010-04-06 2 views
12

i ont une BaseClass de classe abstraite avec une méthode insert() public:méthodes de surcharge et se cacher dans Java

public abstract class BaseClass { 

public void insert(Object object) { 
    // Do something 
} 

} 

qui se prolonge par de nombreuses autres classes. Pour certains de ces classes, cependant, la méthode insert() doit avoir des paramètres supplémentaires, de sorte qu'ils au lieu de passer outre, je surcharge la méthode de la classe de base avec les paramètres requis, par exemple:

public class SampleClass extends BaseClass { 

public void insert(Object object, Long param){ 
    // Do Something 
} 

} 

Maintenant, si je instancier la classe SampleClass, j'ai deux insert() méthodes:

SampleClass sampleClass = new SampleClass(); 
sampleClass.insert(Object object); 
sampleClass.insert(Object object, Long param); 

ce que je voudrais faire est de cacher la méthode insert() définie dans la classe de base, de sorte que seulement la surcharge serait visible:

SampleClass sampleClass = new SampleClass(); 
sampleClass.insert(Object object, Long param); 

Est-ce que cela pourrait être fait en POO?

Répondre

18

Il n'y a aucun moyen de masquer la méthode. Vous pouvez le faire:

@Override 
public void insert(Object ob) { 
    throw new UnsupportedOperationException("not supported"); 
} 

mais c'est tout.

La classe de base crée un contrat. Toutes les sous-classes sont liées par ce contrat. Pensez-y de cette façon:

BaseObject b = new SomeObjectWithoutInsert(); 
b.insert(...); 

Comment est que le code censé savoir qu'il ne dispose pas d'une méthode insert(Object)? Ça ne peut pas.

Votre problème ressemble à un problème de conception. Soit les classes en question ne doivent pas hériter de la classe de base en question, soit cette classe de base ne devrait pas avoir cette méthode. Peut-être pouvez-vous sortir insert() de cette classe, la déplacer vers une sous-classe et avoir des classes qui ont besoin de insert(Object) pour l'étendre, et celles qui ont besoin de insert(Object, Object) pour étendre une sous-classe différente de l'objet de base.

6

Je ne crois pas qu'il y ait une manière propre à cacher complètement une méthode héritée en Java. Dans les cas comme celui-ci, si vous ne pouvez absolument pas supporter cette méthode, je marquerais probablement cette méthode comme @Obsolete dans la classe enfant, et je lui ferais une exception NotImplementedException (ou quelle que soit l'exception équivalente en Java), pour décourager les gens de l'utiliser.

En fin de compte, si vous héritez d'une méthode qui n'a pas de sens pour votre classe enfant, il se pourrait que vous ne devriez pas hériter de cette classe de base du tout. Il se peut également que la classe de base soit mal conçue ou qu'elle comporte trop de comportements, mais cela pourrait valoir la peine d'envisager la hiérarchie de classe. Une autre voie à suivre pourrait être la composition, où votre classe a une instance privée de ce qui était la classe de base, et vous pouvez choisir les méthodes à exposer en les enveloppant dans vos propres méthodes. (Edit: si la classe de base est abstraite, la composition peut ne pas être une option ...)

1

Comme Cletus souligne, ce qui est vraiment un problème de conception, dans ce que vous essayez de créer une classe enfant qui ne respecte pas le contrat de sa catégorie mère.

Il existe des circonstances rares où travailler autour de ceci par ex.lancer une exception peut être souhaitable (ou au moins un compromis acceptable - par exemple, le Java Collections Framework) mais en général c'est un signe de mauvaise conception. Vous voudrez peut-être lire sur the Liskov substitution principle: l'idée que (comme Wikipedia le dit) "si S est un sous-type de T, alors les objets de type T dans un programme peuvent être remplacés par des objets de type S sans en altérer des propriétés souhaitables de ce programme ". En remplaçant une méthode pour lancer une exception ou la cacher d'une autre manière, vous violez ce principe. Si le contrat de la méthode de la classe de base était "insère l'objet courant, ou déclenche une exception" (voir par exemple the JavaDoc for Collection.add()) alors vous pourriez argumenter que vous ne violez pas LSP, mais si cela est inattendu par la plupart des appelants, peut vouloir repenser votre conception sur ces motifs.

1

Cela ressemble à une hiérarchie mal conçue - Si aucun défaut existe

et l'utilisateur ne doit pas appeler la méthode à tout ce que vous pouvez marquer la méthode comme @Deprecated et jeter un UnsupportedOperationException comme d'autres l'ont noté. Cependant - ce n'est vraiment qu'une vérification de l'exécution. @Deprecated ne lance qu'un avertissement de compilateur et la plupart des EDI le marquent d'une certaine manière, mais il n'y a pas de prévention de temps de compilation. Il est aussi vraiment nul parce qu'il est possible d'obtenir la classe enfant en tant que référence de classe parente et d'appeler la méthode dessus sans avertissement que c'est "mauvais" du tout. Dans l'exemple ci-dessous, il n'y aura aucune indication avant l'exécution que quelque chose ne va pas.

Exemple:

// Abstract base builder class 
public abstract class BaseClassBuilder { 
    public final doBuild() { 
     BaseClass base = getBase(); 
     for (Object obj : getObjects() { 
      base.insert(obj); 
     } 
    } 
    protected abstract BaseClass getBase(); 
    protected abstract Object[] getObjects(); 
} 

// implementation using SampleClass 
public class SampleClassBuilder extends BaseClassBuilder { 

    @Override 
    protected BaseClass getBase() { 
     return new SampleClass(); 
    } 

    @Override 
    protected Object[] getObjects() { 
     Object[] obj = new Object[12]; 
     // ... 
     return obj; 
    } 
} 

Cependant, si un défaut raisonnable existe, vous pourriez marquer la méthode héritée comme définitive et de fournir la valeur par défaut à l'intérieur de celui-ci. Cela gère à la fois la mauvaise hiérarchie et empêche les "circonstances imprévues" de l'exemple ci-dessus.

Exemple:

public abstract class BaseClass { 
    public void insert(Object object) { 
     // ... 
    } 
} 

public class SampleClass extends BaseClass { 

    public static final Long DEFAULT_PARAM = 0L; 

    public final void insert(Object object) { 
     this.insert(object, DEFAULT_PARAM); 
    } 

    public void insert(Object object, Long param) { 
     // ... 
    } 
}