Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 生成器模式与配置对象_Java_Oop_Configuration_Builder Pattern - Fatal编程技术网

Java 生成器模式与配置对象

Java 生成器模式与配置对象,java,oop,configuration,builder-pattern,Java,Oop,Configuration,Builder Pattern,生成器模式是创建不可变对象的常用模式,但是创建生成器会有一些编程开销。所以我想知道为什么不简单地使用配置对象 生成器的用法如下所示: Product p = Product.Builder.name("Vodka").alcohol(0.38).size(0.7).price(17.99).build(); class ProductConfig { public String name; public float alcohol; publi

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

生成器的用法如下所示:

Product p = Product.Builder.name("Vodka").alcohol(0.38).size(0.7).price(17.99).build();
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;
    }

}
很明显,这是非常可读和简洁的,但您必须实现生成器:

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);
        }

    }

}
我的想法是,通过使用以下简单的配置对象来减少代码:

Product p = Product.Builder.name("Vodka").alcohol(0.38).size(0.7).price(17.99).build();
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);
这种用法还需要几行代码,但可读性也很强,但是实现要简单得多,对于不熟悉构建器模式的人来说,可能更容易理解。顺便问一下:这个图案有名字吗


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

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


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

在我看来,如果您有验证等功能,那么构建器模式会更加健壮

您的案例中的生成器模式可以更改为执行以下操作:

Product p = new ProductBuilder("pName").alcohol(0.38).size(0.7).price(17.99).build();
build()
方法可以完成构建器所需的所有验证工作。
构建器模式还有几个设计高级门(所有这些可能都不适用于您的情况)。对于deatil,请选中此项

您不应使用公共字段,而应使用受保护或私有字段。对于ACCESIN,您应该使用getter和setter来保持封装

你想用你的模式解决什么问题?生成器模式用于具有许多(可选)参数的对象,以防止大量不同的构造函数或很长的构造函数。在构建过程中,它还使对象保持一致的状态(相对于javabean模式)

builder和“config object”(感觉像个好名字)之间的区别在于,您仍然必须通过构造函数或getter/setter使用相同的参数创建对象。这a)不能解决构造函数问题,或b)使配置对象处于不一致的状态。配置对象的不一致状态并不会真正影响它,但可以将未完成的配置对象作为参数传递。[Michids链接到幻影类型似乎解决了这个问题,但这又一次破坏了可读性(
newfoo
有点糟糕)。]这就是构建器模式的最大优势:您可以在创建对象之前验证参数,并且可以返回任何子类型(类似于工厂)

配置对象对所有必需的参数集有效。我以前在.NET或java中见过很多次这种模式。

您考虑过使用吗


我确实认为构建器(前缀为“with”)的阅读更自然/流畅

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

然而,我最怀念的是,builder模式可以用来提供所谓的“流畅接口”

与此相反:

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();
并不是每个人都喜欢fluent接口,但它们确实非常好地使用了builder模式(所有fluent接口都应该使用builder模式,但并非所有builder模式都是fluent接口)


一些优秀的Java集合,比如Google集合,非常自由而且很好地使用了“流畅的接口”。在你的“更容易输入/更少字符”的方法中,我随时都会选择这些:)

主要的缺点是它不在约书亚的书中,所以无人机无法将它们的头缠绕在它周围

您正在使用一个简单的值对象来保存函数(/method/constructor)所需的多个参数,这并没有错,已经做了很多年了。只要我们没有命名可选参数,我们就必须设计出这样的变通方法——真可惜,不是太阳神的一些该死的辉煌发明

真正的区别在于直接公开字段。Joshua永远不会有一个公共可变字段,但他编写的API将被数百万人使用,其中大多数人都是白痴,这些API必须在未来几十年内安全地发展,他们可以分配许多人-月来设计一个简单的类


我们是谁来解释这一点呢?

我个人认为,构建器模式乍一看为您提供了更清晰的代码,在这些对象实际使用的地方。另一方面,没有getter/setter对于许多希望使用驼峰式getter/setter的框架来说不是很有用。我觉得这是一个严重的倒退

我也喜欢getter/setter,因为您可以清楚地看到自己在做什么:get或set。我觉得与建设者我失去了一点直观的清晰度在这里

我知道很多人都读过一本特定的书,现在突然间,builder模式享受了这种炒作,就好像它是新的iPhone一样。然而,我不是一个早期采用者。我只在“新方法”真正证明在任何领域都能节省大量时间时才使用它,无论是性能、维护、编码

我的实践经验是,我通常更擅长与能手/二传手和建设者合作。它允许我将这些POJO用于任何目的

虽然我看到了配置对象的用途,但我也认为它比构建器的开销更大,为什么?二传手怎么了

也许我们需要发明一个WITH子句: 例如,假设您有

public Class FooBar() {
    private String foo;

    public void setFoo(String bar) { 
      this.foo = bar; 
    }

    public String getFoo() { 
        return this.foo; 
    }
}

public static void main(String []args) {

 FooBar fuBar = new FooBar();
 String myBar;

 with fuBar {
    setFoo("bar");
    myBar = getFoo(); 
 }
}
啊,我不知道。。。我认为这可能会导致更快的代码编写,而不需要所有的内部类麻烦。有人与Oracle Java大师有联系吗

它看起来不像在构建器中使用对象那样干净,但是可以保存构建器