programing

롬복 빌더에서 부동산을 제외하려면 어떻게 해야 합니까?

goodsources 2023. 2. 2. 21:13
반응형

롬복 빌더에서 부동산을 제외하려면 어떻게 해야 합니까?

'XYZClientWrapper'라는 클래스가 있습니다.이 클래스는 다음과 같습니다.

@Builder
XYZClientWrapper{
    String name;
    String domain;
    XYZClient client;
}

속성에 대해 빌드 함수를 생성하지 않을 내용XYZClient client

Lombok은 이러한 사용 사례를 지원합니까?

네, @Builder를 컨스트럭터 또는 정적(공장 출하시) 메서드에 배치할 수 있습니다.이 메서드는 원하는 필드만 포함합니다.

공개:저는 롬복 개발자입니다.

또는 최종, 정적 또는 정적 최종 명령으로 필드를 표시하는 것을 발견했습니다.@Builder이 필드를 무시합니다.

@Builder
public class MyClass {
   private String myField;

   private final String excludeThisField = "bar";
}

롬복 1.16.10

코드로 작성기를 만들고 속성에 대한 개인 설정기를 추가합니다.

@Builder
XYZClientWrapper{
    String name;
    String domain;
    XYZClient client;

    public static class XYZClientWrapperBuilder {
        private XYZClientWrapperBuilder client(XYZClient client) { return this; }
    }
}

여기 제가 선호하는 솔루션이 있습니다.이를 통해 필드를 생성할 수 있습니다.client작성자가 이전에 설정한 다른 필드에 따라 마지막에 표시됩니다.

XYZClientWrapper{
    String name;
    String domain;
    XYZClient client;
    
    @Builder
    public XYZClientWrapper(String name, String domain) {
        this.name = name;
        this.domain = domain;
        this.client = calculateClient();
    }
}

공장에서의 정적 방법의 예

class Car {
   private String name;
   private String model;


   private Engine engine; // we want to ignore setting this
   
   @Builder
   private static Car of(String name, String model){
      Car car=new Car();
      car.name = name;
      car.model = model;
      constructEngine(car); // some static private method to construct engine internally
      return car;  
   }

   private static void constructEngine(Car car) {
       // car.engine = blabla...
       // construct engine internally
   }
}

다음과 같이 사용할 수 있습니다.

Car toyotaCorollaCar=Car.builder().name("Toyota").model("Corolla").build();
// You can see now that Car.builder().engine() is not available

스태틱 방식에 주의해 주십시오.ofbuild()가 호출될 때마다 호출되므로 다음과 같은 작업을 수행합니다.Car.builder().name("Toyota")실제로 값을 설정하지는 않습니다."Toyota"안으로name~하지 않는 한build()호출된 후 생성자 정적 메서드 내에서 로직을 할당합니다.of실행됩니다.

또, 다음의 점에 주의해 주세요.of방법은 비공개로 접근하기 때문에buildmethod는 발신자가 볼 수 있는 유일한 방식입니다.

정적 Builder 클래스의 "쉘"을 구현하고 개인 액세스 수식자로 숨길 메서드를 추가할 수 있으며, 더 이상 Builder에서 액세스할 수 없습니다.마찬가지로 커스텀 메서드를 빌더에 추가할 수도 있습니다.

package com.something;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import java.time.ZonedDateTime;

@Data
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MyClass{

    //The builder will generate a method for this property for us.
    private String anotherProperty;

    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name = "localDateTime", column = @Column(name = "some_date_local_date_time")),
            @AttributeOverride(name = "zoneId", column = @Column(name = "some__date_zone_id"))
    })
    @Getter(AccessLevel.PRIVATE)
    @Setter(AccessLevel.PRIVATE)
    private ZonedDateTimeEmbeddable someDateInternal;

    public ZonedDateTime getSomeDate() {
        return someDateInternal.toZonedDateTime();
    }

    public void setSomeDate(ZonedDateTime someDate) {
        someDateInternal = new ZonedDateTimeEmbeddable(someDate);
    }

    public static class MyClassBuilder {
        //Prevent direct access to the internal private field by pre-creating builder method with private access.
        private MyClassBuilder shipmentDateInternal(ZonedDateTimeEmbeddable zonedDateTimeEmbeddable) {
            return this;
        }

        //Add a builder method because we don't have a field for this Type
        public MyClassBuilder someDate(ZonedDateTime someDate) {
            someDateInternal = new ZonedDateTimeEmbeddable(someDate);
            return this;
        }
    }

}

해결 방법을 하나 더 찾았습니다. 필드를 시작된 최종 래퍼 또는 프록시로 래핑할 수 있습니다.Atomic Reference로 정리하는 가장 쉬운 방법입니다.

@Builder
public class Example {
    private String field1;
    private String field2;
    private final AtomicReference<String> excluded = new AtomicReference<>(null);
}

get 및 set 메서드로 내부와 상호 작용할 수 있지만 빌더에는 표시되지 않습니다.

excluded.set("Some value");
excluded.get();

Lombok을 사용한 클래스에 이른바 '부분 빌더' 추가@Builder도움이 됩니다.요령은 다음과 같이 내부 부분 빌더 클래스를 추가하는 것입니다.

@Getter
@Builder
class Human {
    private final String name;
    private final String surname;
    private final Gender gender;
    private final String prefix; // Should be hidden, depends on gender

    // Partial builder to manage dependent fields, and hidden fields
    public static class HumanBuilder {

        public HumanBuilder gender(final Gender gender) {
            this.gender = gender;
            if (Gender.MALE == gender) {
                this.prefix = "Mr.";
            } else if (Gender.FEMALE == gender) {
                this.prefix = "Ms.";
            } else {
                this.prefix = "";
            }
            return this;
        }

        // This method hides the field from external set 
        private HumanBuilder prefix(final String prefix) {
            return this;
        }

    }

}

PS: @Builder에서는 생성된 빌더 클래스 이름을 변경할 수 있습니다.위의 예에서는 기본 빌더 클래스 이름이 사용되는 것으로 가정하고 있습니다.

다른 접근법이 있습니다.@Delegate그리고.Inner Class는 제외된 필드에 대해 "값 표시"를 지원합니다.

먼저 제외할 필드를 이동한다.Inner Class롬복에게 빌더에 그들을 포함시키지 않기 위해서죠

'우리'를 사용합니다.@Delegate겟터/셋터

예:

@Builder
@Getter @Setter @ToString
class Person {

    private String name;
    private int value;
    /* ... More builder-included fields here */

    @Getter @Setter @ToString
    private class BuilderIgnored {

        private String position; // Not included in the Builder, and remain `null` until p.setPosition(...)
        private String nickname; // Lazy initialized as `name+value`, but we can use setter to set a new value
        /* ... More ignored fields here! ... */

        public String getNickname(){ // Computed value for `nickname`
            if(nickname == null){
                nickname = name+value;
            }
            return nickname;
        }
        /* ... More computed fields' getters here! ... */

    }
    @Delegate @Getter(AccessLevel.NONE) // Delegate Lombok Getters/Setters and custom Getters
    private final BuilderIgnored ignored = new BuilderIgnored();

}

합니다.Person라고 분류하다position ★★★★★★★★★★★★★★★★★」nickname실제로 내부 계층의 분야입니다.

Person p = Person.builder().name("Test").value(123).build();
System.out.println(p); // Person(name=Test, value=123, ignored=Person.BuilderIgnored(position=null, nickname=Test123))
p.setNickname("Hello World");
p.setPosition("Manager");
System.out.println(p); // Person(name=Test, value=123, ignored=Person.BuilderIgnored(position=Manager, nickname=Hello World))

장점:

  • 는 강제로 하지 .final
  • 제외된 필드에 대해 계산된 값 지원
  • 계산 필드가 빌더에 의해 설정된 필드를 참조하도록 허용(즉, 내부 클래스가 비정적 클래스가 되도록 허용
  • 모든 필드 목록을 반복할 필요가 없습니다(예: 생성자에서 제외된 필드를 제외한 모든 필드 나열).
  • Lombok을 .@Builder(:: 성))MyBuilder extends FooBuilder)

단점:

  • '아주 좋다'의입니다.Inner Class ;, 을 합니다.private 수 Getters
  • 따라서 이 접근법에서는 Getters/Setters를 사용하여 제외된 필드에 액세스할 수 없습니다.
  • 은 ""가 "Getters"가호출되었을 때 됩니다..build().

제가 좋아하고 사용하는 방법 중 하나는 이것입니다.필수 매개 변수를 생성자에 유지하고 작성기를 통해 선택 사항을 설정합니다.필요한 수가 많지 않을 때 작동합니다.

class A {
    private int required1;
    private int required2;
    private int optional1;
    private int optional2;

    public A(int required1, int required2) {
        this.required1 = required1;
        this.required2 = required2;
    }

    @Builder(toBuilder = true)
    public A setOptionals(int optional1, int optional2) {
        this.optional1 = optional1;
        this.optional2 = optional2;
        return this;
    }
}

그리고 나서 그것을 건설합니다.

A a = new A(1, 2).builder().optional1(3).optional2(4).build();

이 접근방식의 장점은 옵션에도 기본값을 설정할 수 있다는 것입니다.

이전에 사용한 접근법 중 하나는 인스턴스 필드를 Configuration 필드와 Session 필드로 그룹화하는 것입니다.컨피규레이션필드는 클래스인스턴스로서 Builder에 표시되며 Session 필드는 네스트됩니다. private static class를 통해 할 수 .final인스턴스 (빌더)

다음과 같은 경우:

@Builder
class XYZClientWrapper{
    private String name;
    private String domain;
 
    private static class Session {
        XYZClient client;
    }

    private final Session session = new Session();

    private void initSession() {
        session.client = ...;
    }
 
    public void foo() {
        System.out.println("name: " + name);
        System.out.println("domain: " + domain;
        System.out.println("client: " + session.client);
    }
}

하려면 , 「」를 사용해 .@Builder.Default

언급URL : https://stackoverflow.com/questions/30717640/how-to-exclude-property-from-lombok-builder

반응형