web-dev-qa-db-fra.com

Comment pouvez-vous décomposer un constructeur?

Disons que j'ai une classe ennemie et le constructeur ressemblerait à quelque chose comme:

public Enemy(String name, float width, float height, Vector2 position, 
             float speed, int maxHp, int attackDamage, int defense... etc.){}

Cela semble mauvais parce que le constructeur a tellement de paramètres, mais lorsque je crée un instance ennemi, je dois spécifier toutes ces choses. Je souhaite également que ces attributs dans la classe ennemie, afin que je puisse itérayer une liste d'entre eux et obtenir/définir ces paramètres. Je pensais peut-être sous-classer l'ennemi dans l'ennemi, l'ennemiy, tout en codant sur leur MaxHP, et d'autres attributs spécifiques, mais je perdrais ensuite l'accès à leurs attributs codés si je voulais itérus à travers une liste d'ennemis (consistant en des ennemis, des ennemis, et Enchancks).

J'essaie juste d'apprendre à coder de manière proprement. Si cela fait une différence, je travaille en Java/C++/C #. Tout point dans la bonne direction est apprécié.

21
Travis

La solution consiste à regrouper les paramètres dans des types composites. La largeur et la hauteur sont liées conceptuellement - elles spécifient les dimensions de l'ennemi et seront généralement nécessaires ensemble. Ils pourraient être remplacés par un type Dimensions type, ou peut-être un type Rectangle qui inclut également la position. D'autre part, il peut avoir plus de sens de grouper position et speed dans un type MovementData Type, surtout si l'accélération entre dans l'image. Du contexte, je suppose maxHp, attackDamage, defense, etc. appartenez également à un type Stats. Donc, une signature révisée pourrait ressembler à quelque chose comme ceci:

public Enemy(String name, Dimensions dimensions, MovementData movementData, Stats stats)

Les détails fins de l'endroit où tirer les lignes dépendront du reste de votre code et des données couramment utilisées ensemble.

58
Doval

Vous voudrez peut-être jeter un coup d'œil au Modèle de constructeur . Du lien (avec des exemples de motif par rapport aux alternatives):

[Le modèle Builder est un bon choix lors de la conception de classes dont les constructeurs ou les usines statiques auraient plus d'une poignée de paramètres, en particulier si la plupart de ces paramètres sont facultatifs. Le code client est beaucoup plus facile à lire et à écrire avec des constructeurs qu'avec le modèle de constructeur télescopique traditionnel et les constructeurs sont beaucoup plus sûrs que les JavaBiens.

24
Rory Hunter

Utiliser des sous-classes pour prérégler certaines valeurs n'est pas souhaitable. Seule la sous-classe lorsqu'un nouveau type d'ennemi a un comportement différent ou de nouveaux attributs.

Le modèle d'usine est généralement utilisé pour abstrait sur la classe exacte utilisée, mais il peut également être utilisé pour fournir un modèle pour la création d'objets:

class EnemyFactory {

    // each of these methods is essentially a template for a kind of enemy

    Enemy enemyA(String name, ...) {
        return new Enemy(name, ..., presetValue, ...);
    }

    Enemy enemyB(String name, ...) {
        return new Enemy(name, ..., otherValue, ...);
    }

    Enemy enemyC(String name, ...) {
        return new EnemySubclass(name, ..., otherValue, ...);
    }

    ...
}

EnemyFactory factory = new EnemyFactory();
Enemy a = factory.enemyA("fred", ...);
Enemy b = factory.enemyB("willy", ...);
5
amon

Un exemple de code pour ajouter à la réponse de Rory Hunter (en Java):

public class Enemy{
   private String name;
   private float width;
   ...

   public static class Builder{
       private Enemy instance;

       public Builder(){
           this.instance = new Enemy();
       }


       public Builder withName(String name){
           instance.name = name;
           return this;
       }

       ...

       public Enemy build(){
           return instance;
       }
   }
}

Maintenant, vous pouvez créer de nouvelles instances d'ennemi comme ceci:

Enemy myEnemy = new Enemy.Builder().withName("John").withX(x).build();
0
Toon Borgers

Je réserverais des classements à des classes qui représentent un objet que vous voudrez peut-être utiliser de manière indépendante, par exemple. classe de caractères où tous les caractères, pas seulement les ennemis ont un nom, une vitesse, un maxhp ou une classe pour représenter des sprites qui présentent une présence à l'écran avec une largeur, une hauteur, une position.

Je ne vois rien de mal avec un constructeur avec beaucoup de paramètres d'entrée, mais si vous souhaitez le scinder un peu, vous pouvez avoir un constructeur qui définit la plupart des paramètres et un autre constructeur (surchargé) pouvant être utilisé. Pour définir des celles spécifiques et avoir d'autres définies sur des valeurs par défaut.

Selon la langue que vous choisissez d'utiliser, certaines peuvent définir des valeurs par défaut pour les paramètres d'entrée de votre constructeur comme:

Enemy(float height = 42, float width = 42);
0
Encaitar