dea*_*mon 29 java oop configuration builder-pattern
构建器模式在创建不可变对象时很流行,但是创建构建器会产生一些编程开销.所以我想知道为什么不简单地使用配置对象.
构建器的用法如下所示:
Product p = Product.Builder.name("Vodka").alcohol(0.38).size(0.7).price(17.99).build();
Run Code Online (Sandbox Code Playgroud)
很明显,这是非常易读和简洁的,但您必须实现构建器:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
My idea is, to reduce the code by using a simple config object like 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;
}
}
Run Code Online (Sandbox Code Playgroud)
Usage:
ProductConfig config = new ProductConfig("Vodka");
config.alcohol = 0.38;
config.size = 0.7;
config.price = 17.99;
Product p = new Product(config);
Run Code Online (Sandbox Code Playgroud)
This usage needs a few more lines but is also very readable, but the implementation is much simpler and maybe it is easier to understand for someone who isn't familiar with the builder pattern. By the way: is there a name for this pattern?
Is there a drawback in the config approach that I've overlooked?
小智 16
构建器模式改进了解耦 - 您的Product可以是一个接口,唯一知道实现(或在某些情况下实现)的类是构建器.如果构建器还实现了接口,那么您可以将其注入代码中以进一步增加解耦.
这种解耦意味着您的代码更易于维护且更易于测试.
正如已经指出的那样,你正在失去构建器模式的几个优点(与干净的构建器相比,新的难看并且难以维护和泄漏细节).
然而,我最想念的是构建器模式可用于提供所谓的"流畅接口".
而不是这个:
ProductConfig config = new ProductConfig("Vodka");
config.alcohol = 0.38;
config.size = 0.7;
config.price = 17.99;
Product p = new Product(config);
Run Code Online (Sandbox Code Playgroud)
你可以做:
ProductFactory.create()
.drink("Vodka")
.whereAlcohoolLevelIs(0.38)
.inABottleSized(0.7)
.pricedAt(17.99)
.build();
Run Code Online (Sandbox Code Playgroud)
并不是每个人都喜欢流畅的界面,但它们绝对是对构建器模式的非常好用(所有流畅的接口都应该使用构建器模式,但并非所有构建器模式都是流畅的接口).
一些优秀的Java集合,如Google集合,使得"流畅的接口"非常自由和非常好用.我会在你的"更容易打字/更少字符"的方法中选择这些:)
小智 6
配置模式和构建器模式在功能上是等效的。他们都解决同样的问题 -
消除对多个构造函数签名的需要
只允许在构建期间设置字段
允许消费者仅设置他们关心的值,并为其他值设置逻辑默认值
您想要在其中一种模式中执行的任何操作都可以在另一种模式中执行,例如仅允许使用执行验证的方法设置状态以及使用封装逻辑设置状态。唯一真正的区别是您是否喜欢使用new关键字创建对象或者是否喜欢调用.build()方法。