104 votes

L'idiome des paramètres nommés en Java

Comment implémenter l'idiome des paramètres nommés en Java ? (en particulier pour les constructeurs)

Je recherche une syntaxe semblable à celle de l'Objective-C et non à celle utilisée dans les JavaBeans.

Un petit exemple de code serait le bienvenu.

0 votes

122voto

Laurence Gonsalves Points 50783

Le meilleur idiome Java que j'ai trouvé pour simuler les arguments des mots clés dans les constructeurs est le modèle Builder, décrit dans le document Java efficace 2e édition .

L'idée de base est d'avoir une classe Builder qui possède des setters (mais généralement pas de getters) pour les différents paramètres du constructeur. Il existe également une classe build() méthode. La classe Builder est souvent une classe (statique) imbriquée dans la classe qu'elle sert à construire. Le constructeur de la classe externe est souvent privé.

Le résultat final ressemble à quelque chose comme :

public class Foo {
  public static class Builder {
    public Foo build() {
      return new Foo(this);
    }

    public Builder setSize(int size) {
      this.size = size;
      return this;
    }

    public Builder setColor(Color color) {
      this.color = color;
      return this;
    }

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

    // you can set defaults for these here
    private int size;
    private Color color;
    private String name;
  }

  public static Builder builder() {
      return new Builder();
  }

  private Foo(Builder builder) {
    size = builder.size;
    color = builder.color;
    name = builder.name;
  }

  private final int size;
  private final Color color;
  private final String name;

  // The rest of Foo goes here...
}

Pour créer une instance de Foo, vous écrivez alors quelque chose comme :

Foo foo = Foo.builder()
    .setColor(red)
    .setName("Fred")
    .setSize(42)
    .build();

Les principales mises en garde sont les suivantes :

  1. La configuration du modèle est assez verbeuse (comme vous pouvez le voir). Cela n'en vaut probablement pas la peine, sauf pour les classes que vous prévoyez d'instancier à de nombreux endroits.
  2. Il n'y a pas de contrôle à la compilation pour vérifier que tous les paramètres ont été spécifiés exactement une fois. Vous pouvez ajouter des vérifications au moment de l'exécution, ou vous pouvez utiliser ceci uniquement pour les paramètres optionnels et faire des paramètres obligatoires des paramètres normaux pour Foo ou le constructeur du Builder. (Les gens ne s'inquiètent généralement pas du cas où le même paramètre est défini plusieurs fois).

Vous pouvez également consulter cet article de blog (pas par moi).

13 votes

Il ne s'agit pas vraiment de paramètres nommés au sens où l'entend Objective-C. Cela ressemble plus à une interface fluide. Ce n'est pas vraiment la même chose.

33 votes

J'aime utiliser .withFoo plutôt que .setFoo : newBuilder().withSize(1).withName(1).build() plutôt que newBuilder().setSize(1).setName(1).build()

20 votes

Asaph : oui, je sais. Java n'a pas de paramètres nommés. C'est pourquoi j'ai dit que c'était "le meilleur idiome Java que j'aie vu". simulant les "keyword arguments". Les "paramètres nommés" de l'Objective-C sont également loin d'être idéaux, puisqu'ils imposent un ordre particulier. Il ne s'agit pas de véritables arguments de mots-clés comme en Lisp ou en Python. Au moins, avec le modèle Java Builder, il suffit de se souvenir des noms, et non de l'ordre, comme pour les vrais arguments de type mot-clé.

86voto

irreputable Points 25577

Cela vaut la peine d'être mentionné :

Foo foo = new Foo() {{
    color = red;
    name = "Fred";
    size = 42;
}};

les soi-disant initialisateur à double accolade . Il s'agit en fait d'une classe anonyme avec un initialisateur d'instance.

32 votes

Technique intéressante mais qui semble un peu coûteuse car elle crée une nouvelle classe à chaque fois que je l'utilise dans mon code.

9 votes

Mis à part le formatage automatique, la sous-classe et les avertissements de sérialisation, cette syntaxe est en fait assez proche de la syntaxe C# pour l'initialisation basée sur les propriétés. Cependant, depuis la version 4.0 du langage C#, les paramètres nommés sont également disponibles. Les programmeurs ont donc l'embarras du choix, contrairement aux programmeurs Java qui doivent simuler des idiomes pour éviter de se tirer une balle dans le pied par la suite.

3 votes

Heureux de voir que c'est possible, mais j'ai dû rétrograder car cette solution est coûteuse, comme l'a souligné Red Hyena. J'ai hâte que Java prenne en charge les paramètres nommés comme le fait Python.

26voto

rkj Points 2478

Vous pouvez également essayer de suivre les conseils de aquí .

int value;
int location;
boolean overwrite;
doIt(value=13, location=47, overwrite=true);

C'est un peu verbeux sur le site d'appel, mais c'est celui qui a le moins de frais généraux.

3 votes

C'est une bonne chose, car les frais généraux sont faibles, mais on a l'impression que c'est du bidouillage. Je vais probablement utiliser la méthode Builder() pour les cas où il y a beaucoup d'arguments.

32 votes

Je pense que cela passe complètement à côté de l'intérêt des paramètres nommés. (qui est d'avoir quelque chose associe des noms à des valeurs ). Il n'y a pas d'indication quel qu'il soit si l'on inverse l'ordre. Au lieu de faire cela, je conseillerais d'ajouter simplement un commentaire : doIt( /*value*/ 13, /*location*/ 47, /*overwrite*/ true )

7voto

R Casha Points 51

Si vous utilisez Java 6, vous pouvez utiliser les paramètres variables et l'importation statique pour obtenir un bien meilleur résultat. Vous trouverez plus de détails à ce sujet dans :

http://zinzel.blogspot.com/2010/07/creating-methods-with-named-parameters.html

En bref, vous pourriez avoir quelque chose comme :

go();
go(min(0));
go(min(0), max(100));
go(max(100), min(0));
go(prompt("Enter a value"), min(0), max(100));

2 votes

J'aime bien, mais cela ne résout que la moitié du problème. En Java, il n'est pas possible d'empêcher la transposition accidentelle de paramètres sans perdre la vérification des valeurs requises au moment de la compilation.

2 votes

Sans sécurité de type, c'est pire qu'un simple //commentaire.

6voto

missingfaktor Points 44003

Voici une petite variante de la technique présentée dans Effective Java de Joshua Bloch. Ici, j'ai essayé de rendre le code client plus lisible (ou peut-être plus DSL).

/**
 * Actual class for which we want to implement a 
 * named-parameter pseudo-constructor
 */
class Window{
    protected int x, y, width, height;
    protected boolean isResizable;
    protected String title;

    public void show(){
        // Show the window
        System.out.printf("Window \"%s\" set visible.%n",title);
    }

    /**
     * This class is only used to set the parameter values
     */
    static class HavingProperties extends Window{

        public HavingProperties x(int value){
            this.x=value;
            return this;
        }

        public HavingProperties y(int value){
            this.y=value;
            return this;
        }

        public HavingProperties width(int value){
            this.width=value;
            return this;
        }

        public HavingProperties height(int value){
            this.height=value;
            return this;
        }

        public HavingProperties resizable(boolean value){
            this.isResizable=value;
            return this;
        }

        public HavingProperties title(String value){
            this.title=value;
            return this;
        }
    }
}

public class NamedParameterIdiomInAction {
    public static void main(String... args){
        Window window=new Window.HavingProperties().x(10).y(10).width(100).
                height(100).resizable(true).title("My App");
        window.show();
    }
}

Veuillez noter qu'avec cette variante, vous pouvez également donner des noms significatifs à vos pseudo-constructeurs.

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