[JAVA] Modèle de générateur qui force un ensemble de propriétés requises

Aperçu

environnement

--Java 8 ou version ultérieure

Objets et propriétés cibles (champs)

Lorsque vous souhaitez créer un objet avec une certaine propriété Cette fois, considérons un objet appelé Person comme exemple.

  • ** Propriétés requises à définir ** --Nom de chaîne
  • Âge entier
  • Sexe de chaîne -Hauteur entière
  • ** Propriétés OK facultatives ** --Couleur des yeux --Couleur des cheveux --String hobby (passe-temps)

code

Le code Builder est ci-dessous.

Person



package com.example;
import java.util.Optional;

public class Person {

  private final String name;// Required
  private final Integer age;// Required
  private final String gender;// Required
  private final Integer height;// Required
  private final Optional<String> eyeColor;// Optional(use Optional<String>)
  private final Optional<String> hairColor;// Optional(use Optional<String>)
  private final Optional<String> hobby;// Optional(use Optional<String>)

  Person(Builder.Builder1 builder) {
    this.name = builder.name; 
    this.age = builder.age; 
    this.gender = builder.gender; 
    this.height = builder.height; 
    this.eyeColor = builder.eyeColor; 
    this.hairColor = builder.hairColor; 
    this.hobby = builder.hobby; 
  }
  public static Builder builder() {
    return new Builder();
  }

  public static final class Builder {
    public Builder1 name(String name) {
      return new Builder1(name);
    }
    public static final class Builder1 {
      final String name;
      Integer age;
      String gender;
      Integer height;
      Optional<String> eyeColor;
      Optional<String> hairColor;
      Optional<String> hobby;

      private Builder1(String name) {
        this.name = name;
      }
      public Builder2 age(Integer age) {
        this.age = age;
        return new Builder2(Builder1.this);
      }
    }
    public static final class Builder2 {
      final Builder1 builder;

      private Builder2(Builder1 builder) {
        this.builder = builder;
      }
      public Builder3 gender(String gender) {
        this.builder.gender = gender;
        return new Builder3(this.builder);
      }
    }
    public static final class Builder3 {
      final Builder1 builder;

      private Builder3(Builder1 builder) {
        this.builder = builder;
      }
      public Builder4 height(Integer height) {
        this.builder.height = height;
        return new Builder4(this.builder);
      }
    }
    public static final class Builder4 {
      final Builder1 builder;

      private Builder4(Builder1 builder) {
        this.builder = builder;
      }
      public Builder4 eyeColor(String eyeColor){
        this.builder.eyeColor = Optional.of(eyeColor);
        return this;
      }
      public Builder4 hairColor(String hairColor){
        this.builder.hairColor = Optional.of(hairColor);
        return this;
      }
      public Builder4 hobby(String hobby){
        this.builder.hobby = Optional.of(hobby);
        return this;
      }
      public Person build() {
        return new Person(this.builder);
      }
    }
  }

  public String name() {
    return this.name;
  }
  public Integer age() {
    return this.age;
  }
  public String gender() {
    return this.gender;
  }
  public Integer height() {
    return this.height;
  }
  public Optional<String> eyeColor() {
    return this.eyeColor;
  }
  public Optional<String> hairColor() {
    return this.hairColor;
  }
  public Optional<String> hobby() {
    return this.hobby;
  }

  @Override
  public String toString() {
    return "Person(name=" + this.name + ", age=" + this.age + ", gender=" + this.gender + ", height=" + this.height + ", eyeColor=" + this.eyeColor + ", hairColor=" + this.hairColor + ", hobby=" + this.hobby + ")";
  }

  public void doSomething() {
      // do something
  }
}

point

--Assignez un générateur distinct pour chaque méthode de réglage pour les propriétés requises --Retourne le générateur de la méthode suivante comme valeur de retour du setter

  • De cette manière, les Builders sont retournés en alternance (torsadés) pour chaque propriété.

Code d'utilisateur

package test;
import com.example.Person;
public class Main {
    public static void main(String[] args) {
        Person person = Person.builder().name("Tom").age(20).gender("male").height(200).build();
        System.out.println(person);
    }
}

builder_man.gif

mérite

  • Vous ne pouvez pas ** construire ** sauf si vous spécifiez toutes les propriétés requises.
  • Les propriétés requises peuvent être définies dans un ordre fixe et explicitement (en appelant setter) Inversement, si vous énumérez les arguments comme le ** Constructeur télescopique ** ci-dessous, à mesure que le nombre de propriétés augmente, la visibilité du code de l'utilisateur s'aggravera.

TelescopingConstructor


  public Person(String name, Integer age, String gender, Integer height, String eyeColor, String hairColor, String hobby) {
    this.name = name; 
    this.age = age; 
    this.gender = gender; 
    this.height = height; 
    this.eyeColor = eyeColor; 
    this.hairColor = hairColor; 
    this.hobby = hobby; 
  }

Démérite

  • (pas le code de l'utilisateur) Le code côté Builder devient compliqué et les perspectives deviennent médiocres --Il est pénible d'écrire un code semblable à une plaque de chaudière (*)

(*) Nous avons créé un outil de génération automatique pour atténuer les inconvénients. https://riversun.github.io/java-builder/

Résumé

  • Introduction du modèle Builder qui force la séquence d'initialisation déterminée lors de la création d'un objet ――Il existe de nombreuses variantes de ce modèle, et il semble que la méthode pour l'implémenter en utilisant ** interface ** et la méthode pour le faire sans générer explicitement ** Builder ** soient également utilisées.

Article associé

Recommended Posts