Das Builder- Entwurfsmuster ist eines der beliebtesten in Java.
Es ist einfach, hilft dabei, Objekte unveränderlich zu machen, und kann mit Tools wie @Builder in Project Lombok oder Immutables generiert werden.
Aber ist dieses Muster in Java so praktisch?
Ein Beispiel für diese Methode zur Verkettung von Vorlagen:
public class User {
  private final String firstName;
  private final String lastName;
  User(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  public static Builder builder() {
      return new Builder();
  }
  public static class Builder {
    String firstName;
    String lastName;
    Builder firstName(String value) {
        this.firstName = value;
        return this;
    }
    Builder lastName(String value) {
        this.lastName = value;
        return this;
    }
    public User build() {
        return new User(firstName, lastName);
    }
  }
}
User.Builder builder = User.builder().firstName("Sergey").lastName("Egorov");
if (newRules) {
    builder.firstName("Sergei");
}
User user = builder.build();
:
- User — , .
- , User .
- Builder , User .
- this ( Builder).
… ?
, User:
public class RussianUser extends User {
    final String patronymic;
    RussianUser(String firstName, String lastName, String patronymic) {
        super(firstName, lastName);
        this.patronymic = patronymic;
    }
    public static RussianUser.Builder builder() {
        return new RussianUser.Builder();
    }
    public static class Builder extends User.Builder {
        String patronymic;
        public Builder patronymic(String patronymic) {
            this.patronymic = patronymic;
            return this;
        }
        public RussianUser build() {
            return new RussianUser(firstName, lastName, patronymic);
        }
    }
}
RussianUser me = RussianUser.builder()
    .firstName("Sergei") 
    .patronymic("Valeryevich") 
    .lastName("Egorov")
    .build();
, firstName :
   User.Builder firstName(String value) {
        this.value = value;
        return this;
    }
Java- , this RussianUser.Builder, User.Builder!
:
RussianUser me = RussianUser.builder()
    .patronymic("Valeryevich")
    .firstName("Sergei")
    .lastName("Egorov")
    .build() 
    ;
: self typing
— User.Builder , , :
 public static class Builder<SELF extends Builder<SELF>> {
    SELF firstName(String value) {
        this.firstName = value;
        return (SELF) this;
    }
RussianUser.Builder:
   public static class Builder extends User.Builder<RussianUser.Builder> {
:
RussianUser.builder()
    .firstName("Sergei") 
    .patronymic("Valeryevich") 
    .lastName("Egorov") 
    .build(); 
:
class A<SELF extends A<SELF>> {
    SELF self() {
        return (SELF) this;
    }
}
class B<SELF extends B<SELF>> extends A<SELF> {}
class C extends B<C> {}
, ? … !
, !
new A<A<A<A<A<A<A<...>>>>>>>()
, ( Kotlin):
A a = new A<>();
« » (raw types) diamond operator Java. , , , .
: Self typing Java
: ( , ).
, JEP .
P.S. - , JEP? ;)
Self typing Swift.
Java-:
class A {
    @Self
    void withSomething() {
        System.out.println("something");
    }
}
class B extends A {
    @Self
    void withSomethingElse() {
        System.out.println("something else");
    }
}
new B()
    .withSomething() 
    .withSomethingElse();
, .
javac Self Manifold.
:
, , … ?
public class User {
  
    public static class Builder {
        String firstName;
        String lastName;
        void firstName(String value) {
            this.firstName = value;
        }
        void lastName(String value) {
            this.lastName = value;
        }
        public User build() {
            return new User(firstName, lastName);
        }
    }
}
public class RussianUser extends User {
    
    public static class Builder extends User.Builder {
        String patronymic;
        public void patronymic(String patronymic) {
            this.patronymic = patronymic;
        }
        public RussianUser build() {
            return new RussianUser(firstName, lastName, patronymic);
        }
    }
}
RussianUser.Builder b = RussianUser.builder();
b.firstName("Sergei");
b.patronymic("Valeryevich");
b.lastName("Egorov");
RussianUser user = b.build(); 
« , , Java» — .
, … ?
, , ? !
:
public class User {
  
    public static class Builder {
        public Builder() {
            this.configure();
        }
        protected void configure() {}
:
RussianUser user = new RussianUser.Builder() {
    @Override
    protected void configure() {
        firstName("Sergei"); //  User.Builder
        patronymic("Valeryevich"); //  RussianUser.Builder
        lastName("Egorov"); //  User.Builder
    }
}.build();
, .
«» Java: .
RussianUser user = new RussianUser.Builder() {{
    firstName("Sergei");
    patronymic("Valeryevich");
    lastName("Egorov");
}}.build();
, . Swing/Vaadin ;)
(, , ). . , , , , :
- Java .
- JVM-.
- .
- , .
, Java self typing, Java ( JVM-).
, . , .
, !
P.S. .
. Pivotal Project Reactor, JPoint (5-6 ) — Reactor, !