web-dev-qa-db-fra.com

Désactivation de la méthode héritée sur la classe dérivée

Est-il possible, dans une classe dérivée Java, de "désactiver" une méthode et/ou un champ hérité d'une classe de base?

Par exemple, supposons que vous avez une classe de base Shape qui possède une méthode rotate(). Vous avez également différents types dérivés de la classe Shape: Square, Circle, UpwardArrow, etc. 

Shape a une méthode rotate(). Mais je ne veux pas que rotate() soit disponible pour les utilisateurs de Circle, parce que c'est inutile, ni pour les utilisateurs de UpwardArrow, car je ne veux pas que UpwardArrow puisse effectuer une rotation. 

26

Je ne pense pas que c'est possible. Cependant, vous pouvez affiner davantage la classe Shape avec en supprimant la méthode rotate () de sa spécification et définir à la place une autre sous-classe de Shape appelée RotatableShape et laissez Cercle dériver de Forme et tous les autres {classes rotatives de RotatableShape.

par exemple:

public class Shape{
 //all the generic methods except rotate()
}

public class RotatableShape extends Shape{

 public void rotate(){
    //Some Code here...
 }
}

public class Circle extends Shape{
 //Your implementation specific to Circle
}

public class Rectangle extends RotatableShape{
 //Your implementation specific to Rectangle
}
37
Chandu

Vous pouvez remplacer la méthode spécifique "rotate ()" dans la classe pour laquelle vous souhaitez désactiver cette opération, comme ceci

public void rotate() {
    throw new UnsupportedOperationException();
}
17
Wavyx

Vous avez une mauvaise hiérarchie de classe si vous devez désactiver les méthodes dans les classes enfants. Toute sous-classe devrait pouvoir utiliser sans problème les méthodes de ses super-classes. C'est ce qu'on appelle le "principe de substitution de Liskov" ( https://en.wikipedia.org/wiki/Liskov_substitution_principle ). Vous pouvez en savoir plus à ce sujet dans ce fil de discussion: https://softwareengineering.stackexchange.com/questions/219543/should-a-class-know-about-its-subclasses .

Faites ce que suggère Chandu. Ne mettez pas rotation () en forme. A la place, créez une sous-classe de Shape appelée RotatableShape, et mettez-y rotation (). Ensuite, Circle peut hériter de Shape et Rectangle peut hériter de RotatableShape.

5
Nick Crews

Non. 

  • vous pouvez extraire la méthode uniquement dans la classe Circle (ou une interface implémentée uniquement par cette classe)
  • vous pouvez fournir des implémentations vides ou qui jettent UnsupportedOperationException dans les classes qui ne le supportent pas.
4
Bozho

Déclarer la même fonction dans la classe 'child' écrasera la fonction par défaut déclarée dans la classe de base. Donc, dans votre classe enfant, créez une fonction appelée rotate() qui ne fait rien, qui écrasera le comportement par défaut

3
rsplak

Pouvez-vous utiliser une méthode vide (ne fait rien) pour le cercle? Pour la flèche, je reconsidérerais la hiérarchie des objets

3
Riccardo Cossu

Une solution consiste à définir une seconde méthode appelée (par exemple) boolean isRotatable() et à l'utiliser pour déterminer si les contrôles de rotation sont mis à la disposition de l'utilisateur.

Une autre option serait d’introduire une interface Rotatable et d’utiliser shape instanceof Rotatable pour prendre la décision. (Cependant, je pense que l'approche isRotatable() est plus flexible.)

Dans les deux cas, vous pouvez implémenter la méthode rotate() sur une classe qui ne doit jamais être tournée comme suit:

public void rotate() {
    throw new UnsupportedOperationException("rotate");
}

Le langage Java ne fournit pas un moyen de "supprimer" ou de "désactiver" une méthode dans une sous-classe. Cela violerait le principe de substituabilité et romprait le polymorphisme. Une sous-classe ne peut pas supprimer les membres visibles de l'API de classes parentes.

2
Stephen C

Je ne pense pas que vous puissiez désactiver une méthode de la manière que vous suggérez. 

Dans votre exemple, disons que vous avez une méthode qui prend une forme

public void handleShape(Shape s){
  s.rotate();
}

Ensuite, vous passez un cercle à cette méthode

handleShape(new Circle());

Que devrait-il arriver? Vous demandez essentiellement un changement fondamental du système de types de Java. 

Si Circle est une forme et ne doit pas être pivoté, cela signifie probablement que la forme a été mal conçue et ne devrait pas avoir de méthode de rotation. Vous pouvez ajouter une rotation à une classe différente dans la hiérarchie, telle que RotatableShape, ou éventuellement utiliser une interface Rotatable.

1
richs

Donc, il y a deux possibilités ici. La première est que vous avez un objet qui peut pivoter, mais ne montre aucun changement dans le processus. L'autre est que vous avez un objet qui est défini par sa direction. Chacun doit être traité séparément et à sa manière.

Donc pour cercle, nous avons un talon pour une fonction de rotation car il n’ya pas de changement dans le système. N'aime pas ça, dommage. Je remets mon quiz sur les groupes de points pour écrire ceci.
Pour flèche vers le haut, nous jetons une exception car nous ne voulons pas conduire dans le mauvais sens dans une rue à sens unique et cela devrait être constant de toute façon.

Dans mon cas, je définis un point dans un espace tridimensionnel en héritant des opérations d'une classe définissant un quaternion. Le point tridimensionnel utilise uniquement les 3 coordonnées imaginaires du quaternion et si le quaternion a une valeur non nulle pour le composant réel, il gâchera les opérations essentielles de l'algorithme de rendu hérité du quaternion via les coordonnées tridimensionnelles.

Excusez-moi d’être trop philosophique, cependant, cette question soulève un point valable dans CS sur la façon dont cela devrait être traité. Comme le note Stephen, pouvoir masquer, désactiver ou supprimer la fonction héritée de la classe enfant "... violerait le principe de la substituabilité et romprait le polymorphisme".

Mon cas tombe sous la flèche vers le haut, sauf que je pointe dans l'imagination. J'essaie de tronquer une classe dérivée, ce qui signifie que toute classe de «petits-enfants» (héritant éventuellement d'opérateurs de spin) ne serait plus nécessairement des quaternions. Il serait plus élégant d’éviter de lancer des exceptions, en ajustant la classe de base lors de la conversion de type pour une classe dérivée tronquée. L'alternative serait de définir les coordonnées tridimensionnelles comme une classe séparée avec une variable membre quaternion; L'inconvénient est que la mise en œuvre a trop de colle.

Ensuite, je peux placer les nouvelles opérations de spin dans la classe dérivée pour les coordonnées tridimensionnelles des trois plans (ij, jk, ik), puis les objets avec des sommets en 3D peuvent être pivotés via une boucle et un appel de fonction membre identique pour chaque sommet. . Vous pourriez peut-être suivre vous-même la symétrie avant de commencer à faire pivoter les points définissant la surface de la sphère. C'est pourquoi vous devez utiliser la fonction stub et éventuellement implémenter votre propre drapeau 'constante'.

1
JustKevin

J'avais besoin de la même chose pour un alertdialog personnalisé. J'avais besoin de passer un argument qui n'était disponible qu'au moment de l'émission. J'ai donc implémenté ma méthode show (argument), mais show () a également fonctionné à cause de la superclasse. Il y avait un risque que je puisse invoquer myDlg.show() par accident, sans argument, ce qui provoquerait un crash. Pour m'assurer que la méthode superclass n'est jamais appelée en dehors de ma classe CustomAlertDialog, j'ai ajouté la méthode private static void show(){}. C'est tout.

Donc, pour désactiver un super-méthode, rendez-le privé et statique dans la sous-classe. Dans votre cas, ce serait:

 private void rotate(){}
0
Eugene Kartoyev