在軟體開發過程中,我們經常遇到建立具有眾多屬性的物件變得令人生畏的場景。建構函式混亂會降低程式碼的可讀性。這正是構建器模式的閃光點。構建器模式是一種建立型設計模式,它將複雜物件的構造與其表示分離,提供了一種更清晰、更靈活的物件建立方法。
Builder模式的優點
在我們深入編碼之前,讓我們快速回顧一下利用構建器模式的優勢:
- 靈活性——透過將構造過程與實際物件表示解耦,構建器模式允許我們建立具有不同配置的物件,而不會因多個建構函式或設定器而使我們的程式碼庫混亂
- 可讀性——Builder模式提供了流暢的介面,使我們的程式碼更具可讀性;這使我們和其他開發人員能夠一目瞭然地瞭解複雜物件的構造過程。
- 不變性——構建完成後,構建者可以透過建立不可變物件來強制不變性;這確保了執行緒安全並防止意外修改。
現在,讓我們捲起袖子深入研究程式碼。經典構建器模式
在 Builder 模式的經典實現中,我們建立一個單獨的Builder內部類。該內部類包含設定構造物件的每個屬性的方法。這種結構化方法有利於順序配置過程,確保清晰度和易用性。此外,它還增強了程式碼組織和可讀性,使其更易於理解和維護:
public class Post { private final String title; private final String text; private final String category; Post(Builder builder) { this.title = builder.title; this.text = builder.text; this.category = builder.category; } public String getTitle() { return title; } public String getText() { return text; } public String getCategory() { return category; } public static class Builder { private String title; private String text; private String category; public Builder title(String title) { this.title = title; return this; } public Builder text(String text) { this.text = text; return this; } public Builder category(String category) { this.category = category; return this; } public Post build() { return new Post(this); } } }
|
在構建器類中,我們宣告瞭外部類包含的同一組欄位。Builder類提供了流暢的方法來設定 Post 的每個屬性。此外,它還包含一個build()方法來建立Post例項。現在,我們可以使用Builder建立一個新物件:
Post post = new Post.Builder() .title(<font>"Java Builder Pattern") .text("Explaining how to implement the Builder Pattern in Java") .category("Programming") .build();
|
通用構建器模式
在 Java 8 中,lambda 表示式和方法引用開闢了新的可能性,包括更通用的構建器模式形式。我們的實現引入了一個GenericBuilder類,它可以利用泛型構造各種型別的物件:
public class GenericBuilder<T> { private final Supplier<T> supplier; private GenericBuilder(Supplier<T> supplier) { this.supplier = supplier; } public static <T> GenericBuilder<T> of(Supplier<T> supplier) { return new GenericBuilder<>(supplier); } public <P> GenericBuilder<T> with(BiConsumer<T, P> consumer, P value) { return new GenericBuilder<>(() -> { T object = supplier.get(); consumer.accept(object, value); return object; }); } public T build() { return supplier.get(); } }
|
此類遵循流暢的介面,從of()方法開始建立初始物件例項。然後,with()方法使用 lambda 表示式或方法引用設定物件屬性。GenericBuilder提供了靈活性和可讀性,使我們能夠簡潔地構造每個物件,同時確保型別安全。該模式展示了 Java 8 的表達能力,是複雜構建任務的優雅解決方案。
然而,一個很大的缺點是該解決方案基於類設定器。這意味著我們的屬性不能再像前面的示例那樣是最終的,從而失去了構建器模式提供的不變性。
對於下一個示例,我們將建立一個新的GenericPost類,其中包含預設的無引數建構函式、getter 和 setter:
public class GenericPost { private String title; private String text; private String category; <font>// getters and setters<i> }
|
現在,我們可以使用GenericBuilder建立一個GenericPost:Post post = GenericBuilder.of(GenericPost::new) .with(GenericPost::setTitle, <font>"Java Builder Pattern") .with(GenericPost::setText, "Explaining how to implement the Builder Pattern in Java") .with(GenericPost::setCategory, "Programming") .build();
|
Lombok Builder
Lombok是一個庫,它透過自動生成 getter、setter、equals、hashCode 甚至建構函式等常用方法來簡化 Java 程式碼。
Lombok 最受讚賞的功能之一是它對構建器模式的支援。透過使用@Builder註釋一個類,Lombok 生成一個具有用於設定屬性的流暢方法的構建器類。此註釋消除了手動構建器類實現的需要,顯著減少了冗長
要使用 Lombok,我們需要從Maven 中央儲存庫匯入依賴項:
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.32</version> </dependency>
|
現在,我們可以使用@Builder註釋建立一個新的LombokPost類:@Builder @Getter public class LombokPost { private String title; private String text; private String category; }
|
我們還使用@Setter和@Getter註釋來避免樣板程式碼。然後我們可以使用開箱即用的構建器模式來建立新物件:LombokPost lombokPost = LombokPost.builder() .title(<font>"Java Builder Pattern") .text("Explaining how to implement the Builder Pattern in Java") .category("Programming") .build();
|