详解建造者(builder)模式的创建对象使用方式

抽象类代码

// Builder pattern for class hierarchies

import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;

public abstract class Pizza {
    public enum Topping {HAM, MUSHROOM, ONION, PEPPER, SAUSAGE}
    final Set<Topping> toppings;

    abstract static class Builder<T extends Builder<T>> {
        EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);

        public T addTopping(Topping topping) {
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }

        abstract Pizza build();

        // Subclasses must override this method to return "this"
        protected abstract T self();
    }

    Pizza(Builder<?> builder) {
        toppings = builder.toppings.clone(); // See Item 50
    }
}

这段代码展示了如何使用建造者(Builder)模式来构建具有层次结构的类,特别是用于创建Pizza对象,其中Pizza可以具有多种Topping。下面我将详细解释代码的每一部分:

导入依赖

import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;

这里导入了EnumSet(一个用于枚举类型的集合类)、Objects(包含一些静态工具方法,如requireNonNull)和Set接口。

Pizza类

public abstract class Pizza {
    // ...
}

Pizza`是一个抽象类,代表一个披萨。由于它是抽象的,你不能直接实例化它,但你可以创建它的子类。

Topping 枚举

public enum Topping {HAM, MUSHROOM, ONION, PEPPER, SAUSAGE}

这是一个枚举类型,列出了披萨上可能有的配料。

成员变量

final Set<Topping> toppings;

Pizza类有一个final的Set类型的成员变量toppings,用于存储披萨上的配料。因为它是final`的,所以它只能在构造函数中被初始化,并且之后不能再被更改。

内部抽象类 Builder

abstract static class Builder<T extends Builder<T>> {
    // ...
}

这是Pizza类中的一个静态内部抽象类,用于构建Pizza对象。这个类使用了泛型T,它是Builder类型的一个子类型,这允许我们在方法内部返回当前对象的类型(也称为“泛型自引用”或“递归泛型”)。

Builder 类的成员变量

EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);

Builder类有一个EnumSet类型的成员变量toppings,用于存储用户在构建披萨时选择的配料。开始时,它是空的(noneOf(Topping.class)`)。

addTopping 方法:

public T addTopping(Topping topping) {
    toppings.add(Objects.requireNonNull(topping));
    return self();
}

这个方法允许用户向披萨添加配料。它使用Objects.requireNonNull来确保传入的配料不为null。然后,它将配料添加到toppings集合中,并返回当前Builder对象(通过调用self()方法)。这允许链式调用,如

new Pizza.Builder().addTopping(Topping.HAM).addTopping(Topping.MUSHROOM).build()

build 方法:

 
abstract Pizza build();

这是一个抽象方法,子类必须实现它。该方法应该使用toppings集合中的信息来创建并返回一个新的Pizza对象。

self 方法:

protected abstract T self();

这是一个受保护的抽象方法,子类必须实现它。该方法应该返回当前Builder对象的类型(即T)。这是实现链式调用的关键。

Pizza 类的构造函数:

Pizza(Builder<?> builder) {
    toppings = builder.toppings.clone();
}

Pizza类的构造函数接受一个Builder对象作为参数。由于我们使用了?通配符,所以它可以接受任何类型的Builder对象。在构造函数内部,我们使用clone方法来复制builder.toppings集合,以确保Pizza对象的toppings`成员变量是独立的,并且不会被外部修改。

注意:这个代码片段只展示了Pizza类和Builder类的结构,但没有展示如何创建Pizza的子类或如何实际使用Builder来构建Pizza对象。在实际应用中,你还需要创建Pizza的子类并实现Builder的子类,以及可能的自定义build和self方法。

实现类代码

import java.util.Objects;

public class NyPizza extends Pizza {
    public enum Size { SMALL, MEDIUM, LARGE }
    private final Size size;

    public static class Builder extends Pizza.Builder<Builder> {
        private final Size size;

        public Builder(Size size) {
            this.size = Objects.requireNonNull(size);
        }

        @Override public NyPizza build() {
            return new NyPizza(this);
        }

        @Override protected Builder self() {
            return this;
        }
    }

    private NyPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }
}

public class Calzone extends Pizza {
    private final boolean sauceInside;

    public static class Builder extends Pizza.Builder<Builder> {
        private boolean sauceInside = false; // Default

        public Builder sauceInside() {
            sauceInside = true;
            return this;
        }

        @Override public Calzone build() {
            return new Calzone(this);
        }

        @Override protected Builder self() {
            return this; 
        }
    }

    private Calzone(Builder builder) {
        super(builder);
        sauceInside = builder.sauceInside;
    }
}

这段代码展示了在Java中使用构建者模式(Builder
Pattern)来创建具有不同属性和配置的Pizza类及其子类的实例。构建者模式是一种创建型设计模式,它允许通过链式方法调用来构建复杂对象。这种模式特别适用于那些有许多配置选项的对象。下面是对这段代码的详细解释:

1. 导入Objects类

import java.util.Objects;

这行代码导入了java.util.Objects类,这个类提供了一些静态的实用方法,比如requireNonNull,用于检查给定的对象引用是否为null。

2. NyPizza类

NyPizza类继承自Pizza类,并添加了一个枚举类型的属性size,表示披萨的大小。

枚举类型Size:定义了披萨的三个可能大小(SMALL、MEDIUM、LARGE)。

内部静态类Builder:这是构建者模式的核心。Builder类继承自Pizza.Builder,这表明Pizza类有一个泛型构建者类,用于构建Pizza及其子类的实例。

构造函数:Builder类的构造函数接受一个Size参数,并使用Objects.requireNonNull确保该参数不为null。
build方法:覆盖Pizza.Builder中的build方法,用于创建NyPizza的实例。
self方法:这是一个受保护的方法,返回当前构建器的实例,用于链式调用。
私有构造函数:NyPizza有一个私有构造函数,接受一个Builder对象作为参数,用于初始化披萨的大小。这个构造函数通过调用父类的构造函数(假设父类Pizza有一个接受Pizza.Builder的构造函数)并设置披萨的大小来初始化对象。

3. Calzone类

Calzone类也继承自Pizza类,但添加了一个布尔类型的属性sauceInside,表示酱料是否包裹在面团内部。

内部静态类Builder:与NyPizza类似,Calzone也有一个内部静态Builder类,但它有自己的sauceInside属性,并提供了sauceInside方法来设置这个属性。

默认构造函数:Builder类的默认构造函数将sauceInside设置为false。
sauceInside方法:一个公开的方法,用于设置sauceInside属性为true,并返回构建器实例,支持链式调用。
build和self方法:与NyPizza.Builder中的方法类似,但用于创建Calzone实例。
私有构造函数:Calzone的私有构造函数接受一个Builder对象作为参数,用于初始化酱料是否在面团内部以及(通过调用父类构造函数)可能的其他属性。

总结
这段代码通过构建者模式提供了一种灵活且类型安全的方式来创建Pizza及其子类的实例。每个子类都有一个对应的Builder内部静态类,用于配置该子类特有的属性。通过这种方式,可以创建具有不同配置和属性的披萨实例,同时保持代码的清晰和可维护性。

递归泛型类型

abstract static class Builder<T extends Builder<T>> 

是一个在 Java
中常见的模式,特别是在构建者(Builder)模式中使用泛型时。这个模式的主要目的是提供一个灵活且类型安全的方式来创建和配置复杂对象的实例。下面我将详细解释这个声明的每个部分:

static:

这意味着 Builder 类是一个静态嵌套类。静态嵌套类可以独立于其外部类被实例化,并且它不会持有对外部类实例的隐式引用。
在构建者模式中,Builder 通常被设计为静态的,因为它不依赖于其外部类的任何特定实例,并且它应该能够独立地创建对象。

abstract:

这意味着 Builder 类是一个抽象类,不能直接实例化。通常,你会提供一个或多个非抽象的子类或内部方法来创建 Builder
的实例,并可能提供一些默认实现。 在构建者模式中,Builder
类通常是抽象的,因为它定义了一个接口或契约,该接口或契约描述了如何配置和构建对象。具体的实现细节(例如,设置特定的字段值)可能在子类中定义。

<T extends Builder>:

这是一个泛型声明,它引入了类型参数 T。 T extends Builder 是一个类型约束,它要求 T 必须是 Builder
的一个子类(或 Builder 本身),并且该子类(或
Builder)必须使用它自己(或它的某个子类)作为类型参数。这种技巧被称为“递归泛型类型”。 这种递归泛型类型的使用允许你在
Builder 的方法内部返回 Builder 的正确类型,从而实现流畅的接口(fluent
interface)或链式调用(chaining)。

例如:

public class ComplexObject {

    private final String field1;
    private final int field2;

    private ComplexObject(Builder<?> builder) {
        this.field1 = builder.field1;
        this.field2 = builder.field2;
    }

    public static abstract class Builder<T extends Builder<T>> {
        protected String field1;
        protected int field2;

        public T setField1(String field1) {
            this.field1 = field1;
            return self();
        }

        public T setField2(int field2) {
            this.field2 = field2;
            return self();
        }

        // 这个方法返回“this”的当前类型(T),允许链式调用
        protected abstract T self();

        public ComplexObject build() {
            return new ComplexObject(this);
        }
    }

    // 提供一个具体的子类,以提供 self() 方法的实现
    public static class ConcreteBuilder extends Builder<ConcreteBuilder> {
        @Override
        protected ConcreteBuilder self() {
            return this;
        }
    }

    // 使用示例
    public static void main(String[] args) {
        ComplexObject obj = new ConcreteBuilder()
            .setField1("value1")
            .setField2(42)
            .build();
    }
}

在上面的示例中,ConcreteBuilder 是 Builder 的一个具体子类,它覆盖了 self() 方法并返回 this
的当前类型(ConcreteBuilder),从而允许链式调用。

  • 28
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个双鱼座的测开

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值