[JAVA] Élément 23: Préférez les hiérarchies de classes aux classes balisées

23. Sélectionnez une hiérarchie de classes parmi les classes balisées

Classe étiquetée

Une classe qui montre au moins deux types de caractéristiques et qui bascule entre eux avec des balises qui ont ces caractéristiques dans le champ est appelée une classe balisée. La classe suivante est un exemple, et il est possible de représenter des cercles et des rectangles.

package tryAny.effectiveJava;

class Figure {
    enum Shape {
        RECTANGLE, CIRCLE
    }

    //Tenir le type de forme
    final Shape shape;

    //À utiliser uniquement lorsque la forme est RECTANGLE
    double length;
    double width;

    //À utiliser uniquement lorsque la forme est CERCLE
    double radius;

    //Constructeur pour cercle
    Figure(double radius) {
        shape = Shape.CIRCLE;
        this.radius = radius;
    }

    //Constructeur pour rectangle
    Figure(double length, double width) {
        shape = Shape.RECTANGLE;
        this.length = length;
        this.width = width;
    }

    double area() {
        switch (shape) {
        case RECTANGLE:
            return length * width;
        case CIRCLE:
            return Math.PI * (radius * radius);
        default:
            throw new AssertionError();
        }
    }
}

De telles classes étiquetées présentent de nombreux inconvénients. Voici une liste des inconvénients.

Alternative aux classes marquées: hiérarchie des classes

S'il s'agit d'un langage orienté objet, il peut être amélioré en utilisant une hiérarchie de classes.

La procédure de modification d'une classe balisée vers une hiérarchie de classes est

  1. Créez une classe abstraite et définissez la méthode (méthode area dans l'exemple ci-dessus) dont l'opération est commutée par la valeur de la balise comme méthode abstraite.
  2. Placez les méthodes indépendantes de la valeur des balises et les valeurs de champ dans la classe abstraite (cela n'existe pas dans l'exemple ci-dessus)
  3. Créez une sous-classe pour l'article qui correspond aux caractéristiques de la classe étiquetée. (Cercle, rectangle dans l'exemple ci-dessus)
  4. Mettez un champ spécifique à la caractéristique dans chaque sous-classe. (Rayon du cercle, longueur, largeur du rectangle)

Le résultat de la correction ci-dessus est le suivant.

package tryAny.effectiveJava;

abstract class Figure {
    abstract double area();
}

class Circle extends Figure {
    final double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    @Override
    double area() {
        return Math.PI * (radius * radius);
    }
}

class Rectangle extends Figure {
    final double length;
    final double width;

    Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    double area() {
        return length * width;
    }
}

En faisant cela, les inconvénients de la classe étiquetée mentionnée ci-dessus sont éliminés.

Autres bons points de la hiérarchie des classes

La hiérarchie de classes peut refléter les relations hiérarchiques d'origine entre les types, ce qui peut améliorer la flexibilité (?) Et améliorer la vérification des erreurs lors de la compilation.

Lorsqu'il s'agit d'ajouter un type carré dans l'exemple ci-dessus, il peut être décrit comme suit en utilisant les caractéristiques de la hiérarchie de classes.

class Square extends Rectangle {

    Square(double side) {
        super(side, side);
    }
}

Recommended Posts

Élément 23: Préférez les hiérarchies de classes aux classes balisées
Point 42: Préférez les lambdas aux classes anonymes
Élément 28: Préférer les listes aux tableaux
Rubrique 65: Préférez les interfaces à la réflexion
Rubrique 43: Préférez les références de méthode aux lambdas
Élément 39: Préférez les annotations aux modèles de dénomination
Point 85: Préférez les alternatives à la sérialisation Java
Point 58: Préférez les boucles for-each aux boucles for traditionnelles
Point 61: Préférez les types primitifs aux primitives encadrées
Choisissez une hiérarchie de classes parmi les classes balisées
Élément 81: Préférez les utilitaires de concurrence pour attendre et notifier
Élément 80: Préférez les exécuteurs, les tâches et les flux aux threads
Élément 89: Pour le contrôle d'instance, préférez les types enum à readResolve
Élément 47: Préférez la collecte au flux comme type de retour
Point 25: limiter les fichiers source à une seule classe de premier niveau
Classe à prendre en compte