[JAVA] Builder-Muster, das eine Reihe erforderlicher Eigenschaften erzwingt

Überblick

Umgebung

  • Java 8 oder höher

Zielobjekte und Eigenschaften (Felder)

Wenn Sie ein Objekt mit einer bestimmten Eigenschaft erstellen möchten Betrachten wir dieses Mal ein Objekt namens Person als Beispiel.

  • ** Erforderliche Eigenschaften zum Festlegen **
  • Stringname
  • Ganzzahliges Alter
  • String Geschlecht
  • Ganzzahlige Höhe
  • ** Optionale OK-Eigenschaften ** --String eyeColor
  • String Haarfarbe
  • String Hobby (Hobby)

Code

Der Builder-Code ist unten.

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
  }
}

Punkt

  • Weisen Sie für jede Setter-Methode einen separaten Builder für die erforderlichen Eigenschaften zu
  • Gibt den Builder der nächsten Methode als Rückgabewert des Setters zurück
  • Auf diese Weise werden die Builder für jede Eigenschaft abwechselnd (verdreht) zurückgegeben.

Benutzercode

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

verdienen

  • Sie können nicht ** erstellen **, es sei denn, Sie geben alle erforderlichen Eigenschaften an.
  • Erforderliche Eigenschaften können in einer festen Reihenfolge und explizit festgelegt werden (durch Aufrufen von setter). Wenn Sie dagegen die Argumente wie den folgenden ** Telescoping Constructor ** aufzählen, verschlechtert sich die Sichtbarkeit des Codes auf der Benutzerseite mit zunehmender Anzahl von Eigenschaften.

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; 
  }

Fehler

  • (Nicht der Code des Benutzers) Der Code auf der Builder-Seite wird kompliziert und die Aussichten schlecht
  • Es ist schmerzhaft, kesselplattenähnlichen Code (*) zu schreiben.

(*) Wir haben ein Tool zur automatischen Generierung erstellt, um die Nachteile abzumildern. https://riversun.github.io/java-builder/

Zusammenfassung

  • Einführung des Builder-Musters, das die beim Erstellen eines Objekts festgelegte Initialisierungssequenz erzwingt ――Es gibt viele Variationen dieses Musters, und es scheint, dass auch die Methode zum Implementieren mit ** Schnittstelle ** und die Methode zum expliziten Generieren von ** Builder ** verwendet werden.

In Verbindung stehender Artikel

Recommended Posts