Lombok的建造者模式(builder)与必填参数

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

Lombok's builder with mandatory parameters

问题

If I add @Builder to a class. The builder method is created.
如果我给一个类添加@Builder注解,将会生成一个构建器方法。

I have a requirement where a particular field is mandatory. In this case, the name field is mandatory. Ideally, I would like to declare it like so.
我有一个要求,其中一个特定字段是必需的。在这种情况下,name字段是必需的。理想情况下,我想这样声明。

When googling i found many alternatives like overriding the builder implementation as below:
在进行谷歌搜索时,我发现了许多替代方法,比如重写构建器的实现如下:

And then use it like below:
然后像下面这样使用它:

The problem with above approach is that it still provides the name() and PersonBuilder() method like below, which i don't want:
上述方法的问题在于它仍然提供了像下面这样的name()和PersonBuilder()方法,而我不想要:

Another approach is to add @lombok.nonnull check at name which will force to provide value for name while creating object. but it is a runtime check. it will not force me to provide value for name while creating object.
另一种方法是在name上添加@lombok.nonnull检查,它将强制在创建对象时为name提供值。但这是一个运行时检查,它不会强制我在创建对象时为name提供值。

Is there any additional technique which lombok provides to achieve below:
是否有额外的技术可以使用 lombok 来实现以下目标:

Note: The builder() and name() should not be exposed. The only way to create Person object should be either above or below:
注意:不应该暴露builder()和name()方法。创建Person对象的唯一方式应该是上面或下面的方式:

英文:

If I add @Builder to a class. The builder method is created.

Person.builder().name("john").surname("Smith").build();

I have a requirement where a particular field is mandatory. In this case, the name field is mandatory. Ideally, I would like to declare it like so.

Person.builder("john").surname("Smith").build();

When googling i found many alternatives like overriding the builder implementation as below:

@Builder
public class Person {

    private String name;
    private String surname;

    public static PersonBuilder builder(String name) {
        return new PersonBuilder().name(name);
    }
}

And then use it like below:

Person p = Person.builder("Name").surname("Surname").build();

The problem with above approach is that it still provides the name() and PersonBuilder() method like below, which i don't want:

Person p = Person.builder("Name").surname("Surname").name("").build();
Person p = new Person.PersonBuilder().build;

Another approach is to add @lombok.nonnull check at name which will force to provide value for name while creating object. but it is a runtime check. it will not force me to provide value for name while creating object.

Is there any additional technique which lombok provides to achieve below:

 Person p = Person.builder("Name").surname("Surname").build();

Note: The builder() and name() should not be exposed. The only way to create Person object should be either above or below:

 Person p = Person.builder("Name").build();

答案1

得分: 3

你不能真的用Lombok来做到这一点,参见库作者的解释。但是自己编写这个构建器是否很复杂呢?

public static class PersonBuilder {

    private final String name;
    private String surname;

    PersonBuilder(String name) {
        this.name = name;
    }

    public PersonBuilder surname(String surname) {
        this.surname = surname;
        return this;
    }

    public Person build() {
        return new Person(name, surname);
    }
        
}

使用你已经拥有的相同方法:

public static PersonBuilder builder(String name) {
    return new PersonBuilder(name);
}
英文:

You can't really do it with lombok, see the explanation from the library authors. But is it that complicated to roll this builder on your own?

public static class PersonBuilder {

    private final String name;
    private String surname;

    PersonBuilder(String name) {
        this.name = name;
    }

    public PersonBuilder surname(String surname) {
        this.surname = surname;
        return this;
    }

    public Person build() {
        return new Person(name, surname);
    }
        
}

with the same method that you already have:

    public static PersonBuilder builder(String name) {
        return new PersonBuilder(name);
    }

答案2

得分: 1

尝试将构建器设置为私有。

您是否查看了此评论 https://stackoverflow.com/questions/29885428/required-arguments-with-a-lombok-builder#comment103350941_30867286

我相当确定,一旦再次阅读该线程,您就会找到答案。

附言:如果您的类只有两个字段,最好直接使用构造函数。

英文:

Try to make the builder private.

Did you check this comment https://stackoverflow.com/questions/29885428/required-arguments-with-a-lombok-builder#comment103350941_30867286

I am pretty sure you will find out once read the thread one more time.

P.S. If you have a class with only two field better use directly a constructor.

答案3

得分: 0

最佳实践:

import lombok.Builder;
import lombok.NonNull;

@Builder(builderMethodName = "privateBuilder")
public class Person {
    @NonNull
    private String name;
    private String surname;

    public static class PersonNameBuilder {
        public PersonBuilder name(String name) {
            return Person.privateBuilder().name(name);
        }
    }

    private static class PersonExtraBuilder extends PersonBuilder {
        @Deprecated
        @Override
        public PersonBuilder name(String name) {
            return this;
        }
    }

    public static PersonNameBuilder builder(String name) {
        return new PersonNameBuilder();
    }

    private static PersonExtraBuilder privateBuilder() {
        return new PersonExtraBuilder();
    }
}

用法:

PersonNameBuilder nameBuilder = Person.builder();
PersonBuilder builder = nameBuilder.name("John");
Person p1 = builder.surname("Smith").build();

// Or
Person p2 = Person.builder().name("John").surname("Smith").build();

// The last `.name("")` will not work, and it will be marked as Deprecated by IDE.
Person p3 = Person.builder().name("John").surname("Smith").name("").build();
英文:

Best Practice:

import lombok.Builder;
import lombok.NonNull;

@Builder(builderMethodName = "privateBuilder")
public class Person {
	@NonNull
    private String name;
    private String surname;

    public static class PersonNameBuilder {
		public PersonBuilder name(String name) {
			return Person.privateBuilder().name(name);
		}
	}
    
    private static class PersonExtraBuilder extends PersonBuilder{
    	@Deprecated
    	@Override
    	public PersonBuilder name(String name) {
    		return this;
    	}
    }

    public static PersonNameBuilder builder(String name) {
        return new PersonNameBuilder();
    }

    private static PersonExtraBuilder privateBuilder(){
    	return new PersonExtraBuilder();
    }
}

Usage:

PersonNameBuilder nameBuilder = Person.builder();
PersonBuilder builder = nameBuilder.name("John");
Person p1 = builder.surname("Smith").build();

// Or
Person p2 = Person.builder().name("John").surname("Smith").build();

// The last `.name("")` will not work, and it will be marked as Deprecated by IDE.
Person p3 = Person.builder().name("John").surname("Smith").name("").build();

huangapple
  • 本文由 发表于 2020年7月28日 14:28:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/63128224.html
匿名

发表评论

匿名网友

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

确定