Java 中的建造者模式:清晰地构建自定义对象
建造者设计模式的意图
Java 中的建造者设计模式是一种基本的创建型模式,它允许逐步构建复杂对象。它将复杂对象的构建与它的表示分离,这样同一个构建过程可以创建不同的表示。
建造者模式的详细说明以及现实世界中的例子
现实世界的例子
Java 建造者模式在对象创建涉及大量参数的场景中特别有用。
想象一下你在一家熟食店构建一个可定制的三明治。在这个场景中,建造者设计模式将涉及一个三明治建造者,它允许你指定三明治的每个组件,例如面包类型、肉类、奶酪、蔬菜和调味品。与其从头开始知道如何构建三明治,不如使用三明治建造者一步一步地添加每个所需的组件,确保你得到你想要的三明治。这种将构建与最终产品表示分离的做法确保了同一个构建过程可以根据指定的组件生成不同类型的三明治。
通俗地讲
允许你创建对象的不同的“口味”,同时避免构造函数污染。在可能存在多个“口味”的对象或创建对象涉及许多步骤的情况下很有用。
维基百科说
建造者模式是一种对象创建软件设计模式,其目的是寻找解决望远镜构造函数反模式的解决方案。
考虑到这一点,让我们解释什么是望远镜构造函数反模式。在某些时候,我们都遇到过类似于下面的构造函数
public Hero(Profession profession,String name,HairType hairType,HairColor hairColor,Armor armor,Weapon weapon){
// Value assignments
}
正如你所看到的,构造函数参数的数量很快就会变得难以承受,从而难以理解它们的排列方式。此外,如果你决定在将来添加更多选项,此参数列表可能会继续增长。这就是所谓的望远镜构造函数反模式。
Java 中建造者模式的编程示例
在这个 Java 建造者模式示例中,我们使用不同的属性构建不同类型的Hero
对象。
想象一个角色扮演游戏的角色生成器。最简单的选择是让电脑为你生成角色。但是,如果你更喜欢手动选择角色细节,例如职业、性别、头发颜色等,那么角色创建就变成了一个逐步的过程,直到所有选择都完成才结束。
一种更明智的方法是使用建造者模式。首先,让我们考虑我们要创建的Hero
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
}
然后我们有Builder
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
然后可以像这样使用它
public static void main(String[] args) {
var mage = new Hero.Builder(Profession.MAGE, "Riobard")
.withHairColor(HairColor.BLACK)
.withWeapon(Weapon.DAGGER)
.build();
LOGGER.info(mage.toString());
var warrior = new Hero.Builder(Profession.WARRIOR, "Amberjill")
.withHairColor(HairColor.BLOND)
.withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL).withWeapon(Weapon.SWORD)
.build();
LOGGER.info(warrior.toString());
var thief = new Hero.Builder(Profession.THIEF, "Desmond")
.withHairType(HairType.BALD)
.withWeapon(Weapon.BOW)
.build();
LOGGER.info(thief.toString());
}
程序输出
16:28:06.058 [main] INFO com.iluwatar.builder.App -- This is a mage named Riobard with black hair and wielding a dagger.
16:28:06.060 [main] INFO com.iluwatar.builder.App -- This is a warrior named Amberjill with blond long curly hair wearing chain mail and wielding a sword.
16:28:06.060 [main] INFO com.iluwatar.builder.App -- This is a thief named Desmond with bald head and wielding a bow.
建造者模式的类图
何时在 Java 中使用建造者模式
使用建造者模式的情况
- 建造者模式非常适合需要复杂对象创建的 Java 应用程序。
- 创建复杂对象的算法应该独立于构成对象的各个部分以及它们的组装方式
- 构建过程必须允许构建的对象具有不同的表示形式
- 当一个产品需要很多步骤来创建,并且这些步骤需要按照特定的顺序执行时,它特别有用
建造者模式的 Java 教程
Java 中建造者模式的现实世界应用
- Java 中用于构建字符串的 StringBuilder。
- java.lang.StringBuffer 用于创建可变字符串对象。
- Java.nio.ByteBuffer 以及类似的缓冲区,例如 FloatBuffer、IntBuffer 等
- javax.swing.GroupLayout.Group#addComponent()
- IDE 中用于构建 UI 组件的各种 GUI 建造者。
- 所有实现 java.lang.Appendable 的类
- Apache Camel 建造者
- Apache Commons Option.Builder
建造者模式的优势和权衡
优点
- 与其他创建型模式相比,对构建过程有更多控制
- 支持逐步构建对象,延迟构建步骤或递归执行步骤
- 可以构建需要复杂子对象组装的对象。最终产品与构成它的各个部分及其组装过程分离
- 单一职责原则。你可以将复杂的构建代码与产品的业务逻辑分离
权衡
- 代码的整体复杂性可能会增加,因为该模式需要创建多个新类
- 由于需要创建多个建造者对象,可能会增加内存使用量
相关的 Java 设计模式
- 抽象工厂:可以与建造者一起使用来构建复杂对象的各个部分。
- 原型:建造者通常从原型创建对象。
- 步骤建造者:它是建造者模式的一种变体,它使用逐步方法生成复杂对象。当需要使用大量可选参数构建对象,并且希望避免望远镜构造函数反模式时,步骤建造者模式是一个不错的选择。