7 votes

Modèle de construction : quelle variante est préférée ?

Je parcourais le livre Effective Java, et je créais des notes pour mes références futures, je suis tombé sur le modèle Builder.

J'ai compris ce qu'il est et comment il est censé être utilisé, et j'ai créé deux exemples de variations du modèle de construction.

J'aurais besoin d'aide pour établir une liste des différences et des avantages de chacun d'entre eux ? Eh bien, j'ai certainement remarqué que, Example 1 expose moins de méthodes, donc moins restrictives, et plus générique, ce qui lui permet d'être utilisé de manière plus souple.

Pouvez-vous me signaler d'autres choses que j'ai manquées ?

Exemple 1

package item2;

/**
 * @author Sudhakar Duraiswamy
 *
 */
public  class Vehicle {

    private String type;
    private int wheels;

    interface Builder<T>{
        public  T build();
    }

    public static class CarBuilder implements Builder<Vehicle>{
        private String type;
        private int wheels;     

        CarBuilder createVehicle(){
            this.type= "Car";
            return this;
        }

        CarBuilder addWheels(int wheels){
            this.wheels = wheels;
            return this;
        }

        public Vehicle build(){
            Vehicle v = new Vehicle();
            v.type = type;
            v.wheels = wheels;
            return v;
        }               
    }

    public static class TruckBuilder implements Builder<Vehicle>{       
        private String type;
        private int wheels; 

        TruckBuilder createVehicle(){           
            this.type= "Truck";
            return this;
        }

        TruckBuilder addWheels(int wheels){
            this.wheels = wheels;
            return this;
        }

        public Vehicle build(){
            Vehicle v = new Vehicle();
            v.type = type;
            v.wheels = wheels;
            return v;
        }
    }   

    public Vehicle(){

    }

    public static void main(String[] args) {
        //This builds a car with 4 wheels
        Vehicle car = new Vehicle.CarBuilder().createVehicle().addWheels(4).build();

        //THis builds a Truck with 10 wheels
        Vehicle truck = new Vehicle.TruckBuilder().createVehicle().addWheels(10).build();

    }
}

Exemple 2

package item2;
/**
 * @author Sudhakar Duraiswamy
 *
 */
public  class Vehicle2 {

    private String type;
    private int wheels;

    interface Builder<T>{
        public  T build();      
        public String getType();
        public int getWheels() ;
    }

    public static class CarBuilder implements Builder<Vehicle2>{
        private String type;
        private int wheels;     

        public String getType() {
            return type;
        }
        public int getWheels() {
            return wheels;
        }

        CarBuilder createVehicle(){
            this.type= "Car";
            return this;
        }

        CarBuilder addWheels(int wheels){
            this.wheels = wheels;
            return this;
        }

        public Vehicle2 build(){        
            return new Vehicle2(this);
        }               
    }

    public static class TruckBuilder implements Builder<Vehicle2>{      
        private String type;
        private int wheels; 

        public String getType() {
            return type;
        }

        public int getWheels() {
            return wheels;
        }

        TruckBuilder createVehicle(){           
            this.type= "Truck";
            return this;
        }

        TruckBuilder addWheels(int wheels){
            this.wheels = wheels;
            return this;
        }

        public Vehicle2 build(){
            return new Vehicle2(this);
        }
    }

public Vehicle2(Builder<? extends Vehicle2> builder){
    Vehicle2 v = new Vehicle2();
    v.type = builder.getType();
    v.wheels = builder.getWheels();
}

    public Vehicle2(){
    }

    public static void main(String[] args) {            
        //This builds a car with 4 wheels
        Vehicle2 car = new Vehicle2.CarBuilder().createVehicle().addWheels(4).build();

        //THis builds a Truck with 10 wheels
        Vehicle2 truck = new Vehicle2.TruckBuilder().createVehicle().addWheels(10).build();
    }
}

9voto

JB Nizet Points 250258

Aucune de ces réponses.

La première ne permet pas de construire un véhicule immuable, ce qui explique souvent l'utilisation du modèle Builder.

Le deuxième exemple est une variation du premier qui permet d'obtenir des informations du constructeur en utilisant des méthodes getter supplémentaires. Mais ces méthodes ne sont utilisées nulle part, sauf dans le constructeur du véhicule, qui a accès aux champs du constructeur directement. Je ne vois pas l'intérêt de les ajouter.

Je vois deux autres points importants à améliorer :

  1. Les deux types de constructeurs font exactement la même chose. Il n'y a pas besoin de deux types. Un seul est suffisant.
  2. Qu'est-ce que le createVehicle() doit être effectuée par le constructeur du constructeur. Si vous construisez un CarBuilder, c'est évidemment pour construire une voiture, donc le type du véhicule doit être défini dès la construction du constructeur. Voici comment je l'écrirais :

.

public final class Vehicle {

    private final String type;
    private final int wheels;

    private Vehicle(Builder builder) {
        this.type = builder.type;
        this.wheels = builder.wheels;
    }

    public static Builder carBuilder() {
        return new Builder("car");
    }

    public static Builder truckBuilder() {
        return new Builder("truck");
    }

    public static class Builder {
        private final String type;
        private int wheels;

        private Builder(String type) {
            this.type = type;
        }

        public Builder addWheels(int wheels){
            this.wheels = wheels;
            return this;
        }

        public Vehicle build() {
            return new Vehicle(this);
        }               
    }

    public static void main(String[] args) {
        Vehicle car = Vehicle.carBuilder().addWheels(4).build();
        Vehicle truck = Vehicle.truckBuilder().addWheels(10).build();
    }
}

3voto

Matthias Meid Points 8473

Il existe également une troisième variante, avec moins de code :

Au lieu de disposer de leurs propres champs d'instance, les constructeurs pourraient également modifier l'état de la base de données de l'entreprise. Vehicle . Les classes internes peuvent écrire des membres privés de leur classe externe :

class Vehicle {
  private int wheels;

  private Vehicle() {}

  public static class Builder {
    private boolean building = true;
    private Vehicle vehicle = new Vehicle();

    public Builder buildWheels(int wheels) {
      if(!this.building) throw new IllegalStateException();
      this.vehicle.wheels = wheels;
      return this;
    }

    public Vehicle build() {
      this.building = false;
      return this.vehicle;
    }
  }
}

Puisque les champs sont privés et que vous permettez qu'il soit construit seulement une fois ( building drapeau), construit Vehicle Les instances sont toujours immuable aux consommateurs même si les champs ne peuvent pas être final plus (plus de realio-trulio immutabilité voir l'article du blog d'Eric qui est sur C# mais les concepts sont similaires).

Vous devez être plus prudent car les champs non finaux ne doivent pas être initialisés lors de la construction de l'objet (imposé par le compilateur) et vous devez vérifier la valeur de l'attribut building énoncer soigneusement. Vous enregistrez cependant une copie supplémentaire complète de tous les champs d'instance. En général, ceci est utile si vous avez un ensemble assez large de variables d'instance qui sont construites avec un nombre assez restreint de méthodes, où chaque méthode construit quelques champs à la fois.

Je sais que cela ne met pas en évidence les avantages ou les inconvénients de vos approches. Cependant, cette approche peut permettre d'économiser beaucoup de code supplémentaire si vous n'avez pas besoin que les champs soient final .

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