生成器模式:我们不能简化生成生成器对象的过程吗?

huangapple go评论78阅读模式
英文:

Builder Pattern: Can't we simplify the creation of a builder object?

问题

为了更好地理解构建者模式,我有一些(新手)问题。主要是,为什么我们不能简化构建者对象的创建呢?

不是这样:

public final class Foo {

    private final String name;
    private final String description;

    private Foo(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    }

    public static class Builder {
        private String name;
        private String description;

        public Builder setName(String name) {
            this.name = name;
            return this;
        }

        public Builder setDescription(String description) {
            this.description = description;
            return this;
        }

        public Foo build() {
            return new Foo(name, description);
        }

    }

}

// 使用它
Foo f = new Foo.Builder().setName("test").setDescription("description").build();

为什么不只使用这个:

public final class Foo {

    private String name;
    private String description;

    public String getName() {
        return name;
    }

    public String getDescription() {
        return description;
    } 

    public Foo setName(String name){
       this.name=name;
       return this; 
    }

    public Foo setDescription(String description){
       this.description=description;
       return this; 
    }
}

// 使用它
Foo f = new Foo().setName("test").setDescription("description");

我明白第一个版本可能在你想要构建不可变对象时使用,但除此之外,为什么我不能只使用第二个版本呢?它更简单。请尽可能提供示例。

英文:

Just getting my head around the Builder pattern and I have a few (noob) questions. Mainly, why can't we just simplify the creation of a builder object?

Instead of this:

public final class Foo {

	private final String name;
	private final String description;

	private Foo(String name, String description) {
		this.name = name;
		this.description = description;
	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

	public static class Builder {
		private String name;
		private String description;

		public Builder setName(String name) {
			this.name = name;
			return this;
		}

		public Builder setDescription(String description) {
			this.description = description;
			return this;
		}

		public Foo build() {
			return new Foo(name, description);
		}

	}

}

//Use it
Foo f = new Foo.Builder().setName("test").setDescription("description").build();

Why not just use this?

public final class Foo {

    private String name;
    private String description;

    public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	} 

    public Foo setName(String name){
       this.name=name;
       return this; 
    }

    public Foo setDescription(String description){
       this.description=description;
       return this; 
    }
}

//Use it
Foo f = new Foo().setName("test").set("description");

I see maybe the first one is used when you want to build an immutable object, but other than that why can't I just use the second one instead? It's far simpler. Please provide examples as much as possible.

答案1

得分: 1

建造者模式在对象构建过程中存在一些在构建期间有效但在对象构建完成后无效的操作时非常有用。

是的,这在构建不可变对象时最为明显,但在仅当对象的某些方面是不可变时,它同样经常适用。常见的例子包括:

  • 通常,在构建期间会指定对象的标识(例如一个人的名字),但在此之后不允许更改;
  • 注入的依赖项,例如要使用的数据库、日志等,在构建后通常不允许更改;
  • 工厂和策略在构建后通常不允许更改,因为对象在所有输出中都期望保持一致性。

此外,有时在有效对象上的设置器会产生一些效果,比如触发事件等,在构建过程中你可能不希望发生这些效果。有时你可以通过复杂的规则来解决,比如“在设置完所有内容之前不要附加监听器”,但应尽量避免使用复杂的规则。

英文:

The builder pattern is useful when there are operations that are valid during construction that are not valid once the object is built.

Yes, this is most obviously the case for building immutable objects, but it also applies very often when only some aspects of the object are immutable. Common examples are:

  • Often the identifier for an object (a person's name, for example) is specified during construction, but is not allowed to change after that;
  • Injected dependencies, like the database to use, the log to use, etc., are often not allowed to change after construction;
  • Factories and strategies are often not allowed to change after construction, because the object expects consistency across all their outputs.

Also, sometimes a setter on a valid object would have an effect, like dispatching an event, for example, that you don't want to happen during construction. You can sometimes get around that via complicated rules like "don't attach listeners until you're finished setting stuff up", but complicated rules are to be avoided.

答案2

得分: 1

使用你的第二种方法,我将能够通过以下方式创建一个对象。

Foo f = new Foo().setDescription("description");

这意味着,在您的系统中,我们创建了一个没有名称的对象。
如果我们再举一个例子,那将更加自明。

Employee emp = new Employee().setDescription("manager");

这意味着我在公司里雇佣了一个没有知道姓名的经理。

基本上,通过使用build(),我们还可以确保在创建对象时提供了所有必需的成员变量。如果需要的话,我们甚至可以进行基本的验证。

public Foo build() {
    if (name == null) {
        throw Exception();
    } else {
        return new Foo(name, description);
    }
}
英文:

Using your Second approach , i will be able to create a Object by doing.

> Foo f = new Foo().setDescription("description");

Which means, We java created a object in your system without a name.<br>
If we take another example which will be must self explanatory .

> Employee emp = new Employee ().setDescription("manager");

Which means i hired a manager in a company without even know name.

Basically with Build() , we can also make sure all the required member variable are provided while creating a object. We can even do basic vaidation if needed.<br>

public Foo build() {
				if(name == null){
					throw Exception();
				else
					return new Foo(name, description);
}

答案3

得分: 0

你的方式是“JavaBeans 模式”,来自effective java item2: "JavaBean 模式" 的构建在多个调用之间进行拆分,一个 JavaBean 可能在构建过程中部分状态不一致。该类不能仅通过检查构造函数参数的有效性来强制保持一致性。在对象处于不一致状态时尝试使用它可能会导致与包含错误的代码相去甚远的失败,从而难以调试。相关的缺点是,JavaBeans 模式排除了使类变成不可变的可能性,并且需要程序员付出额外的努力来确保线程安全。"构建者模式" 是线程安全且更易读的。

你可以使用 Lombok 的 @Builder 注解使一个类成为"构建者模式"。

英文:

Your way is "JavaBeans Patterns", From effectice java item2:"JavaBean Patterns" construction is split across multiple calls, a
JavaBean may be in an inconsistent state partway
through its construction. The class does not have the option of
enforcing consistency merely by checking the validity of the
constructor parameters. Attempting to use an object when it’s in
an inconsistent state may cause failures that are far removed from
the code containing the bug and hence difficult to debug. A related
disadvantage is that the JavaBeans pattern precludes the
possibility of making a class immutable and
requires added effort on the part of the programmer to ensure
thread safety. "Builder Pattern" is thread safe and more readable.

you can use lombok @Builder annotation to make a class "Builder Pattern".

huangapple
  • 本文由 发表于 2020年5月4日 09:11:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/61583719.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定