生成器模式与配置对象

2022-09-01 07:45:13

生成器模式通常用于创建不可变对象,但创建生成器需要一些编程开销。所以我想知道为什么不简单地使用一个配置对象。

构建器的用法如下所示:

Product p = Product.Builder.name("Vodka").alcohol(0.38).size(0.7).price(17.99).build();

很明显,这是非常可读和简洁的,但你必须实现构建器:

public class Product {

    public final String name;
    public final float alcohol;
    public final float size;
    public final float price;

    private Product(Builder builder) {
        this.name = builder.name;
        this.alcohol = builder.alcohol;
        this.size = builder.size;
        this.price = builder.price;
    }

    public static class Builder {

        private String name;
        private float alcohol;
        private float size;
        private float price;

        // mandatory
        public static Builder name(String name) {
            Builder b = new Builder();
            b.name = name;
            return b;
        }

        public Builder alcohol(float alcohol) {
            this.alcohol = alcohol;
            return.this;
        }

        public Builder size(float size) {
            this.size = size;
            return.this;
        }

        public Builder price(float price) {
            this.price = price;
            return.this;
        }

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

    }

}

我的想法是,通过使用像这样的简单配置对象来减少代码:

class ProductConfig {

        public String name;
        public float alcohol;
        public float size;
        public float price;

        // name is still mandatory
        public ProductConfig(String name) {
            this.name = name;
        }

}

public class Product {

    public final String name;
    public final float alcohol;
    public final float size;
    public final float price;

    public Product(ProductConfig config) {
        this.name = config.name;
        this.alcohol = config.alcohol;
        this.size = config.size;
        this.price = config.price;
    }

}

用法:

ProductConfig config = new ProductConfig("Vodka");
config.alcohol = 0.38;
config.size = 0.7;
config.price = 17.99;
Product p = new Product(config);

这种用法需要更多的行,但也非常可读,但实现要简单得多,也许对于不熟悉构建器模式的人来说更容易理解。顺便说一句:这个模式有名字吗?

配置方法中是否有我忽略的缺点?


答案 1

生成器模式改进了解耦 - 您的 Product 可以是一个接口,并且了解实现(或在某些情况下,在某些情况下)的唯一类是生成器。如果构建器还实现了一个接口,那么您可以将它注入到代码中以进一步增加解耦。

这种解耦意味着您的代码更易于维护且更易于测试。


答案 2

正如已经指出的那样,您正在失去构建器模式的几个优点(与干净的构建器相比,新的是丑陋的,更难维护和泄漏细节)。

然而,我最想念的是,构建器模式可以用来提供所谓的“流畅接口”。

取而代之的是:

ProductConfig config = new ProductConfig("Vodka");
config.alcohol = 0.38;
config.size = 0.7;
config.price = 17.99;
Product p = new Product(config);

您可以执行以下操作:

ProductFactory.create()
    .drink("Vodka")
    .whereAlcohoolLevelIs(0.38)
    .inABottleSized(0.7)
    .pricedAt(17.99)
    .build();

不是每个人都喜欢流畅的接口,但它们绝对是构建器模式的一个非常好的用法(所有流畅的接口都应该使用构建器模式,但并非所有的构建器模式都是流畅的接口)。

一些伟大的Java集合,如Google集合,既非常自由,也很好地利用了“流畅的界面”。我会在任何一天选择这些,而不是你的“更容易打字/更少的字符”方法:)