我正在学习构建器模式,到目前为止我理解它,它是用于初始化的常用模式的一个很好的替代方法:
伸缩构造函数模式
JavaBean Pattern
问题是,我真的不想从我的域模型中的对象中删除getter和setter。我总是喜欢把它们当作POJO。我不喜欢它的原因之一是: 如果我不使用POJO,那么在使用ORM框架时注释变量并不容易......
所以这是我的疑惑: - 是否可以在不使用静态内部类的情况下实现构建器模式? - 如果我必须使用内部类来使用构建器模式,你认为保持getter和setter是正确的吗? - 我为练习做了一个小例子,我试图避开内部类。 你能告诉我你怎么看待它?
产品
public class Product
{
private String color;
private int price;
public Product() {
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String toString() {
return getColor() + "\n" + getPrice();
}
}
生成器
public class Builder
{
private Product product;
public Builder() {
product = new Product();
}
public Builder withColor(String color) {
product.setColor(color);
return this;
}
public Builder withPrice(int price) {
product.setPrice(price);
return this;
}
public Product build() {
return product;
}
}**
客户端
public class Client
{
public static void main(String[] args) {
System.out.println(new Builder().withColor("Black").withPrice(11).build());
System.out.println("-----------------------------------------------------");
System.out.println(new Builder().withColor("Blue").withPrice(12).build());
}
}
答案 0 :(得分:12)
Builder模式对于创建不可变对象很有用,并且避免使用带有可选参数的多个构造函数。
IMO使用Builder模式构建可以使用setter更新的POJO是没用的。您只需创建一个附加类。
根据使用的ORM框架,可能不需要存在setter方法。但只能通过反思来分配成员价值。
产品类别:
public final class Product {
private final String color;
private final int price;
public Product(Builder builder) {
this.color = builder.getColor();
this.price = builder.getPrice();
}
public String getColor() {
return color;
}
public int getPrice() {
return price;
}
public String toString() {
return getColor() + "\n" + getPrice();
}
}
构建器类:
public final class Builder {
private String color;
private int price;
public Builder() {
// Assign any default values
}
public Builder color(String color) {
this.color = color;
return this;
}
public Builder price(int price) {
this.price = price;
return this;
}
protected String getColor() {
return color;
}
protected int getPrice() {
return price;
}
public Product build() {
return new Product(this);
}
}
答案 1 :(得分:4)
构建器模式在不可变对象的上下文中最有用。根据定义,不可变对象没有setter。所以他们所有的属性都必须被压缩到构造函数中。这是构建器模式派上用场的地方。它允许您将复杂的不可变对象的初始化拆分为多个自解释指令,这样您就不需要在您的代码中使用像这个虚构示例的构造函数调用,您无法分辨哪个参数执行了什么:
Thing foo = new Thing(1, 125, Thing.SOMETHING, new Whatchamacallit(17, 676), getStuffManager(StuffManager.ZOMG), true, false, false, maybe);
我没有发现当创建的对象是可变的时,Builder模式会创建任何重要的值。您通过构建器执行的所有操作也可以直接使用创建的对象完成。
另外,我认为上面的程序不是构建器模式的教科书示例。您通常不会通过将构建器传递给构造函数来创建对象。您可以通过在构建器上调用create
方法来创建对象,然后将其所有属性传递给对象的构造函数。这种模式的优点是它使构建器有机会检查其内部状态的一致性,并可能在开始构建对象之前抛出异常。
java StringBuilder类是一个很好的例子(在这种情况下,创建方法为tostring
)。
答案 2 :(得分:3)
在这里使用建筑师实际上有什么收获?
我无法看到:您可以直接创建新产品并在其上使用getter和setter。如果你有一个简单的POJO那么绝对没有错:
Product p=new Product();
p.setColour("Black");
p.setPrice(11);
doSomethingWith(p);
保存一些输入字符是恕我直言,不值得引入新的类/构建器抽象。
构建器在以下情况下更有用:
答案 3 :(得分:1)
构建器模式非常适合生成不可变类,但它仍然是可变类的一个很好的选择。
在任何对象包含许多需要在构造期间设置的字段的情况下,构建器是一种合理的设计选择;特别是如果可以为几个值选择合理的默认值。
您是否使用内部课程取决于您的目标。如果希望通过构建器强制构造,可以将构建器定义为内部类,并确保外部类只有一个私有构造函数。
答案 4 :(得分:1)
以下是GoF书中的Builder合作: 合作 1.客户端创建Director对象并使用所需的Builder对象对其进行配置。 2.每当构建产品的一部分时,主任都会通知建筑商。 3. Builder处理来自导演的请求并添加产品的部件。 3.客户端从构建器中检索产品。
Builder模式侧重于逐步构建复杂对象。 Builder将产品作为最后一步返回。在没有setter的情况下返回的类可能与immutable一样好。使用setter,它可以被修改。内部课程有助于掩盖细节。
另一点值得注意的是,创作设计模式背后的主要动机是客户并不担心创建产品。对象创建过程委托给工厂,构建器等。客户端不必担心对象创建。它将指定它想要的内容,并将根据委派的创建过程获得它。
答案 5 :(得分:1)
是否可以在不使用静态的情况下实现构建器模式 内在的课程?
当然,是的。就Builder设计模式而言,如果Builder是内部类,它没有任何区别。
- 如果我必须使用内部类来使用构建器模式,你认为保持getter和setter是正确的吗?
是的,没关系。它有点像,使用某个模板构建对象,然后根据需要自定义它。
- 我为练习做了一个小例子,我试图避开内心 类。你能告诉我你对它的看法吗?
两个问题 -
Product p = new Product();
p.setColor(c);
p.setPrice(prc);
然后你所展示的方式几乎没有任何好处。 Product
不应依赖Builder
。 答案 6 :(得分:1)
我发现自己在考虑吸气剂是否对建造者有益。构建器通常不应用作返回值 - 单个方法或类应负责使用构建器创建实体。因此,方法(或类)应保留所需的信息,而不是将其取回。
出于这些原因,我决定不在构建器类中使用任何getter。 Builder只有setter(可以是带有Abc(...),setAbc(...)或abc(...)),build()以及一些私有方法,比如validate()。
使用类Product,示例实体如下所示:
class Product {
private final String color;
private final int price;
private Product(ProductBuilder builder) {
this.color = builder.color;
this.price = builder.price;
}
// equals, hashCode, toString
public builder() {
return new ProductBuilder(this);
}
public static emptyBuilder() {
return new ProductBuilder();
}
public String getColor() {
return color;
}
public int getPrice() {
return price;
}
现在,构建器类是实体的内部类,它允许我使用私有构造函数。
public static class ProductBuilder {
private String color;
private int price;
private ProductBuilder() {
}
private ProductBuilder(Product entity) {
this.color = entity.color;
this.price = entity.price;
}
public ProductBuilder withColor(String color) {
this.color = color;
return this;
}
public ProductBuilder withPrice(int price) {
this.price = price;
return this;
}
public Product build() {
return new Product(this.validate());
}
private ProductBuilder validate() {
if (color == null) {
throw new IllegalStateException("color is null");
}
return this;
}
}
正如您所看到的,我添加了方法builder()
以将构建器作为实例的副本,并将emptyBuilder()
作为工厂方法来隐藏构造函数(可能有更好的名称)。< / p>
此外,在构造不可变类时,请确保内部的所有内容也是不可变的。收藏很棘手,你必须复制,然后在其上使用Collections.unmodifiable *(...),以确保没有人对不可修改的包装下的集合有引用。
编辑:据说,如果你有抽象的超类,你需要 getter。这是夸大其辞。如果你有一个包含所有参数的构造函数,你只需要它。如果您像我一样通过构建器,则会得到:
class Product extends Something { ...
private Product(ProductBuilder builder) {
super(builder); // that one must be protected, not private
...
}
public static class ProductBuilder extends SomethingBuilder { ...
protected ProductBuilder validate() {
super.validate();
...
}
}
}
那么,我们需要 getter吗?这一次,不是真的。没有他们,我们仍然没事。其他一些想法?
答案 7 :(得分:0)
Builder 是关于几件事的,您可能只想使用一个方面:流畅的API 。只需更改设置者即可返回this
而不是void
,您可以最大限度地满足您的需求。然后你可以使用chained-setter习语:return new MyBean().setCheese(cheese).setBacon(bacon);
另外,术语“POJO”与“JavaBean”并不相同。事实上,有时这两个术语被用作对立面。 POJO的意义在于它不符合而不是Java对象。例如,它可能使用public
个变量。