2 votes

Meilleure pratique pour les champs de sous-classe/superclasse

J'ai du mal à choisir entre ces trois façons de gérer les variables de champ pour une sous-classe et une superclasse.

Méthode 1 :

public abstract class Vehicle {
    public abstract int getNumberOfWheels();
    public abstract int getCost();
}

public class Car extends Vehicle {
    private int numberOfWheels;
    private int cost;

    public Car() {
        this.numberOfWheels = 4;
        this.cost = 10000;
    }

    public int getNumberOfWheels() {
        return numberOfWheels;
    }

    public int getCost() {
        return cost;
    }
}

Avec cette méthode, je dois implémenter les mêmes méthodes getter en double dans chaque sous-classe de Vehicle. J'imagine que ce serait un problème avec des méthodes getter plus compliquées, qui doivent être dupliquées et éventuellement maintenues.

Méthode 2 :

public abstract class Vehicle {
    private int numberOfWheels;
    private int cost;

    public int getNumberOfWheels() {
        return numberOfWheels;
    }

    public int getCost() {
        return cost;
    }

    public void setNumberOfWheels(int numberOfWheels) {
        this.numberOfWheels = numberOfWheels;
    }

    public void setCost(int cost) {
        this.cost = cost;
    }
}

public class Car extends Vehicle {
    private int numberOfWheels;
    private int cost;

    public Car() {
        super.setNumberOfWheels(4);
        super.setCost(10000);
    }
}

Avec cette méthode, je dois mettre en œuvre des méthodes de paramétrage que je ne souhaite peut-être pas avoir. Je ne voudrais peut-être pas que d'autres classes puissent modifier les champs, même dans le même package.

Méthode 3 :

public abstract class Vehicle {
    private int numberOfWheels;
    private int cost;

    public class Vehicle(int numberOfWheels, int cost) {
        this.numberOfWheels = numberOfWheels;
        this.cost = cost;
    }

    public int getNumberOfWheels() {
        return numberOfWheels;
    }

    public int getCost() {
        return cost;
    }
}

public class Car extends Vehicle {
    private int numberOfWheels;
    private int cost;

    public Car() {
        super(4, 10000);
    }
}

Avec cette méthode et avec beaucoup de champs, le nombre de paramètres du constructeur va devenir énorme, ce qui n'est pas normal.

Il semble que ce soit un problème suffisamment courant pour qu'il existe une sorte de "meilleure pratique". Existe-t-il une meilleure façon de procéder ?

3voto

GhostCat Points 83269

Plusieurs réflexions ici :

  1. C'est en fait bon que tu n'entres pas dans le protégé Il faut éviter, dans la mesure du possible, de partager des champs entre les classes de base et les classes d'extension.
  2. De même, c'est aussi bon pratique pour éviter d'utiliser des setters. Cela exclut en quelque sorte votre deuxième option.

Plus loin...

Vous pourriez réécrire votre sous-classe dans l'option 1 pour :

@Override // always use that when OVERRIDING methods!
public int getNumberOfWheels() { return 4; }

Dans votre option 1, ces chiffres sont en fait constantes comme votre code est no montrant tout moyen de changer ces valeurs. Il n'est donc pas nécessaire d'utiliser des champs dans les classes dérivées ! À moins, bien sûr, que vous n'imaginiez différents types de voitures, et que vous n'ayez besoin de prévoir 3 ou 5 roues également. Dans ce cas, vous proposeriez un ctor par défaut, et un autre qui prendrait le nombre de roues (pour ensuite le stocker dans une classe dérivée). final propriété).

Dans ce cas, vous avez raison de dire que, lorsque de nombreuses informations sont nécessaires, l'option 3, qui consiste à utiliser des constructeurs, vous "explosera" à la figure. Mais : ce ne serait de toute façon qu'une conséquence d'un problème de conception. Parce que : on devrait être conservateur sur le nombre de champs de toute façon. En d'autres termes, si votre classe comporte tellement de champs que les initialiser via les constructeurs semble être un problème, c'est une indication que vous avez trop de champs en premier lieu ! Dans une telle situation, vous devriez regarder dans votre fichier modèle pour déterminer quelles propriétés vraiment appartiennent à votre classe.

Exemple : dans votre code, vous représentez le "coût" comme une propriété de votre classe de base. Mais est-ce vraiment le cas ? Son "prix" est-il vraiment un élément essentiel propriété de tout véhicule ? Ce que je veux dire, c'est qu'une voiture n'est qu'une voiture ; elle ne se "soucie" pas de sa valeur. Cette valeur est extrinsèque la propriété, que autre imposerait à cette voiture. Autrement dit, un véhicule n'a pas nécessairement besoin d'une propriété prix/coût. Vous ne commencez à penser à cela que lorsque les véhicules sont des entités dans un certain plus grand contexte qui traite des valeurs de ses entités. Ainsi, un autre EntityManager pourrait être un meilleur endroit pour garder la trace des véhicules et de leur valeur (actuelle) correspondante.

0voto

aUserHimself Points 1275

Les bonnes pratiques sont ici plutôt relatives ; dans votre cas, cela dépend de ce que vous essayez d'obtenir.

  1. Est-ce que toute sous-classe de Vehicle ont un nombre de roues et un coût associé ? Si la réponse est oui, il est bon de les ajouter à la superclasse. Si vous avez TrackVehicle comme sous-classe, alors numberOfWheels n'est pas applicable ici et n'appartient donc pas à la superclasse.

  2. Posez-vous la question : avez-vous vraiment besoin de setters ? Devrez-vous modifier l'état de votre instance après sa création ? Si non, ne les ajoutez pas : vous pouvez créer un constructeur dans la superclasse qui prend le nombre total de paramètres requis et l'utiliser dans chaque sous-classe :

    public Car(int numberOfWheels, int cost) {
        super(numberOfWheels, cost);
    }
  3. En essayant de deviner votre intention, ce serait ma méthode :

    public abstract class Vehicle {
        private int numberOfWheels;
        private int cost;
    
        public Vehicle(int numberOfWheels, int cost) {
            this.numberOfWheels = numberOfWheels;
            this.cost = cost;
        }
        public int getNumberOfWheels() {
            return numberOfWheels;
        }
        public int getCost(){
            return cost;
        }
    }

    et une sous-classe spécifique où chaque Car a 4 roues et un coût pour le monde extérieur qui est en fait beaucoup plus grand que le coût initial (juste pour montrer le fait que vous pouvez surcharger une méthode si nécessaire, pas besoin de la dupliquer).

    public class Car extends Vehicle {
        public Car(int cost) {
            super(4, cost);
        }
        @Override
        public int getCost(){
            return cost * 2;
        }
    }
  4. En ce qui concerne le problème des "paramètres de constructeur qui vont devenir énormes", jetez un coup d'œil aux modèles de conception "Builder". ( Java efficace - Modèle de construction )

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