23 votes

Limites des sous-classes OOP

En java, quelle est la bonne façon de concevoir une sous-classe qui réduit la fonctionnalité de la super-classe ?

Par exemple, considérons la classe "Man", qui possède la fonction "See" et la sous-classe "BlindMan" qui ne devrait pas avoir cette fonction, mais devrait avoir tout le reste que "Man" possède.

La seule solution que j'ai trouvée est d'avoir une classe abstraite "Man", et deux sous-classes "SeeingMan" et "BlindMan", avec SeeinMan ajoutant une fonction "See".

Cependant, le problème avec cette solution est que si je veux maintenant ajouter une classe "DeafMan", qu'est-ce qu'elle étend ? SeeingMan ? et que se passe-t-il si cet homme est à la fois sourd et aveugle ?

1voto

Mostafa Jamareh Points 870

Vous pouvez utiliser les booléens

ex : isSeeing()

et dans votre fonction, vous pourriez l'utiliser dans votre instruction if else.

1voto

Uooo Points 2824

En java, quelle est la bonne façon de concevoir une sous-classe qui réduit la fonctionnalité de la super-classe ?

Il s'agit en fait de savoir comment l'héritage peut réduire la fonctionnalité. Un exemple de ceci en Java auquel je peux penser est la fonction Collections#unmodifyableList qui dit :

Renvoie une vue non modifiable de la liste spécifiée. Cette méthode permet aux modules de fournir aux utilisateurs un accès en "lecture seule" aux listes internes. Les opérations d'interrogation sur la liste renvoyée "lisent à travers" la liste spécifiée, et les tentatives de modification de la liste renvoyée, que ce soit directement ou par l'intermédiaire de son itérateur, entraînent un message d'erreur UnsupportedOperationException .

C'est donc ce que je ferais si je voulais supprimer une certaine fonctionnalité. Cependant, assurez-vous que l'utilisation de cette fonctionnalité est claire, par exemple, indiquez dans la Javadoc de BlindMan que see() entraînera une exception.

Toutefois, si vous souhaitez "réduire" plusieurs fonctionnalités, peut-être de manière indépendante, et les modifier au fil du temps, je préférerais utiliser des variables plutôt que l'héritage. En fin de compte, vous n'étendez pas la superclasse, alors pourquoi abuser de l'héritage pour cela ? Ce que vous avez, c'est un humain avec différents propriétés .

Le comportement des méthodes doit être documenté. Je pourrais penser à la classe suivante pour votre cas d'utilisation :

public class Human {
    private boolean seeing;

    public void setSeeing(boolean seeing) { ...}
    public boolean isSeeing() { ... }

    /**
     *  Returns what the human sees at the moment, or null
     *  if he/she can't see (seeing is false).
     */
    public String see() {
        if(seeing){
            return "I can see a tree!";
        }else{
            return null;
        }
    }

    // same goes for hearing
}

1voto

Alpedar Points 781

Laissez l'humain faire les choses à sa façon, donnez-lui des tâches, pas des ordres.

Voir fait partie d'une activité, alors laissez-le utiliser la vue (ou non) de manière indépendante.

Eg lui dit de voyager quelque part. Un homme sain utilisera la vue, un aveugle utilisera d'autres sens et sera moins efficace (sauf dans l'obscurité totale).

Si la vision est nécessaire pour une tâche donnée (par exemple, un garde sur une tour de garde), vous devez demander quelle est la qualité de leur vue (il n'y a pas d'aveugles ayant une vue exceptionnelle).

Parfois, vous voulez leur demander ce qu'ils voient (et ne pas vous soucier de ce qu'ils entendent, etc.) Alors demandez simplement et attendez-vous à ce que les aveugles (et autres malvoyants) ne voient rien.

Si vous voulez que les humains soient des objets passifs et qu'un autre objet les traite, il existe une approche non encore mentionnée : regardez la programmation entité-componet utilisée dans la programmation des jeux. Il s'agit essentiellement d'utiliser la composition de manière générique. Les entités ne contiennent que l'identité, les composants contiennent des données sur certains aspects de l'entité (par exemple, la vue pourrait être le nombre de dioptries ou d'autres statistiques plus utiles) et les systèmes traitent des ensembles d'entités qui ont la combinaison de composants requise par un système donné. Le système de vue pourrait avoir besoin du composant de vue et créer le composant seenEntities contenant les entités que l'entité actuelle voit en ce moment. Un autre système pourrait fusionner les résultats de tous les sens et les utiliser pour effectuer quelque chose d'utile.

1voto

Lukasz Points 9471

Par exemple, considérons la classe "Homme", qui a la fonction "Voir" et la sous-classe "BlindMan" qui ne devrait pas avoir cette fonction.

Vous n'avez pas tout compris. Un aveugle a la fonction "voir" qui ne fait rien (parce qu'il n'y a pas de lien entre les capteurs et la partie appropriée du cerveau, ou parce que les capteurs ne fonctionnent pas (ils renvoient une liste vide de pixels ou une image de taille 0).

Une bonne analogie : un Writer a une fonction flush() mais ce qui rend cette fonction pour StringWriter ?

/**
 * Flush the stream.
 */
public void flush() { 
}

Eh bien, rien. Il n'y a rien à tirer la chasse. OK mais pourquoi le close() jette IOException ?

public void close() throws IOException {
}

Ce n'est pas parfait, mais le code fonctionne pour tous les types d'écrivains, même ceux pour lesquels flush n'est pas pertinent.

Mais attendez, même pour la fonction d'homme voyant see() peut retourner une liste nulle ou vide. Par exemple, quand il fait trop sombre. Il suffit de vérifier les valeurs nulles/vides et le code fonctionnera bien avec cette conception.

0voto

Angelo Neuschitzer Points 6166

Vous pouvez lancer une exception dans les cas où vous ne voulez pas que la fonction soit appelée.

Par exemple, dans votre scénario : InablityException

comme ça :

public interface Man {

    public Object see() throws InabilityException;
    public Object hear() throws InabilityException;

}

public class BlindMan implements Man {
    public Object see() throws InabilityException {
       throw new InabilityException("blind people don't see");
    }

    public Object hear() {
       return "what I hear";
    }
}

Et vice-versa pour le Sourd-Man.

La même chose fonctionne si l'homme est un class au lieu d'un interface .

Vous pourriez (et devriez) combiner cela avec la réponse de @Pataschu. https://stackoverflow.com/a/17080626/881272 y throw el Exception si hasWorkingEyes() retourne faux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X