Effective Java: Builder-Pattern

7 Jahre nach der ersten Auflage ist das Buch “Effective Java” von Joshua Bloch nun endlich in der zweiten Auflage erschienen. Der Klassiker wurde komplett runderneuert: Best-Practises für ‘neue’ Sprachelemente wie Generics und Enums kamen hinzu, veraltete Kapitel (wie der Ersatz von C-Strukturen) wurden gestrichen.

Neu ist auch das “Builder-Pattern”. Es kommt zum Einsatz, wenn ein Objekt viele optionale Variablen besitzt. Die bisherige, klassische Variante bei solchen Objekten ist das Schreiben von mehreren Konstruktoren (’telescoping constructor’), die über unterschiedliche Anzahl von Parametern verfügen. Allerdings sinkt die Lesbarkeit bei mehr als 6 Parametern gewaltig (vor allem wenn die Parameter vom gleichen Typ sind).

Das “Builder-Pattern” verzichtet auf die ‘telescoping constructors’ und arbeitet stattdessen mit einer statischen inneren Klasse, die für das Erzeugen einer Instanz der äusseren Klasse zuständig ist. Der Konstruktor des Builder-Objekts enthält alle “Pflicht”-Variablen, die optionalen Variablen werden über (verkettbare) Methodenaufrufe hinzugefügt. Abschliessend wird die build Methode aufgerufen, die ein unveränderliches Objekt der äusseren Klasse erzeugt. Der Konstruktor der äusseren Klasse ist privat, d.h. nur ein Builder kann ein Objekt tatsächlich instanzieren:

Hier ein Beispiel:

  1. package ch.javablog.builderpattern;
  2.  
  3. import java.math.BigDecimal;
  4.  
  5. public class Product {
  6.         // all fields are final: immutable object
  7.         private final String id;
  8.         private final BigDecimal price;
  9.         private final String salesDescription;
  10.         private final Product baseProduct;
  11.         private final boolean approved;
  12.  
  13.         private Product (Builder builder) {
  14.                 // private Constructor can only be called from Builder
  15.                 this.id = builder.id;
  16.                 this.price = builder.price;
  17.                 this.salesDescription = builder.salesDescription;
  18.                 this.baseProduct = builder.baseProduct;
  19.                 this.approved = builder.approved;
  20.         }
  21.  
  22.         public String getId() {
  23.                 return id;
  24.         }
  25.  
  26.         public BigDecimal getPrice() {
  27.                 return price;
  28.         }
  29.  
  30.         public String getSalesDescription() {
  31.                 return salesDescription;
  32.         }
  33.  
  34.         public Product getBaseProduct() {
  35.                 return baseProduct;
  36.         }
  37.  
  38.         public boolean isApproved() {
  39.                 return approved;
  40.         }
  41.  
  42.         public static class Builder {
  43.                 // mandatory parameter
  44.                 private final String id;
  45.                 private final BigDecimal price;
  46.  
  47.                 // optional
  48.                 private String salesDescription = “”;
  49.                 private Product baseProduct     = null;
  50.                 private boolean approved        = true;
  51.  
  52.                 public Builder(String id, BigDecimal price) {
  53.                         this.id = id;
  54.                         this.price = price;
  55.                 }
  56.                 public Builder salesDescription(String salesDescription) {
  57.                         this.salesDescription = salesDescription;
  58.                         return this;
  59.                 }
  60.                 public Builder baseProduct(Product baseProduct) {
  61.                         this.baseProduct = baseProduct;
  62.                         return this;
  63.                 }
  64.                 public Builder approved(boolean approved) {
  65.                         this.approved = approved;
  66.                         return this;
  67.                 }
  68.  
  69.                 public Product build() {
  70.                         return new Product(this);
  71.                 }
  72.         }
  73. }
  74.  
  75. public class ProductClient {
  76.         public static void main(Stringargs) {
  77.                 BigDecimal price = BigDecimal.valueOf(36.5);
  78.                 Product.Builder builder = new Product.Builder(“050-0047”,price);
  79.                 // create Product using the builder
  80.                 Product p = builder
  81.                                 .salesDescription(“great product”)
  82.                                 .approved(false)
  83.                                 .build();
  84.         }
  85. }

Comments are closed.