programing

유효한 Java의 Builder 패턴

newsource 2022. 11. 7. 22:38

유효한 Java의 Builder 패턴

나는 최근에 조슈아 블로흐의 이펙트 자바를 읽기 시작했다.빌더 패턴[책 속 아이템 2]의 아이디어가 매우 흥미로웠습니다.프로젝트에 구현하려고 했지만 컴파일 오류가 발생했습니다.제가 하려던 일은 기본적으로 다음과 같습니다.

여러 속성을 가진 클래스 및 해당 빌더 클래스:

public class NutritionalFacts {
    private int sodium;
    private int fat;
    private int carbo;

    public class Builder {
        private int sodium;
        private int fat;
        private int carbo;

        public Builder(int s) {
            this.sodium = s;
        }

        public Builder fat(int f) {
            this.fat = f;
            return this;
        }

        public Builder carbo(int c) {
            this.carbo = c;
            return this;
        }

        public NutritionalFacts build() {
            return new NutritionalFacts(this);
        }
    }

    private NutritionalFacts(Builder b) {
        this.sodium = b.sodium;
        this.fat = b.fat;
        this.carbo = b.carbo;
    }
}

위의 클래스를 사용하려고 하는 클래스:

public class Main {
    public static void main(String args[]) {
        NutritionalFacts n = 
            new NutritionalFacts.Builder(10).carbo(23).fat(1).build();
    }
}

다음의 컴파일러 에러가 발생.

effective java를 포함하는 둘러싸인 인스턴스.BuilderPattern영양 팩트Builder는 NutritionalFacts n = new NutritionalFacts가 필요합니다.Builder(10). carbo(23). fat(1).빌드();

나는 그 메시지가 무엇을 의미하는지 이해할 수 없다.설명해 주세요.위의 코드는 Bloch가 그의 책에서 제시한 예시와 유사합니다.

빌더를 a로 하다static수업. 그럼 효과가 있을 거야정적이 아닌 경우에는 소유 클래스의 인스턴스가 필요합니다.중요한 것은 클래스의 인스턴스가 존재하지 않는 것, 빌더 없이 인스턴스를 만드는 것조차 금지하는 것입니다.

public class NutritionFacts {
    public static class Builder {
    }
}

레퍼런스:중첩된 클래스

Builder 클래스를 정적으로 만들어야 하며 필드를 최종화하고 이러한 값을 가져올 getter를 가져야 합니다.이러한 값에는 세터를 제공하지 마십시오.이렇게 하면 당신의 계급은 완전히 불변할 것이다.

public class NutritionalFacts {
    private final int sodium;
    private final int fat;
    private final int carbo;

    public int getSodium(){
        return sodium;
    }

    public int getFat(){
        return fat;
    }

    public int getCarbo(){
        return carbo;
    }

    public static class Builder {
        private int sodium;
        private int fat;
        private int carbo;

        public Builder sodium(int s) {
            this.sodium = s;
            return this;
        }

        public Builder fat(int f) {
            this.fat = f;
            return this;
        }

        public Builder carbo(int c) {
            this.carbo = c;
            return this;
        }

        public NutritionalFacts build() {
            return new NutritionalFacts(this);
        }
    }

    private NutritionalFacts(Builder b) {
        this.sodium = b.sodium;
        this.fat = b.fat;
        this.carbo = b.carbo;
    }
}

이제 다음과 같이 속성을 설정할 수 있습니다.

NutritionalFacts n = new NutritionalFacts.Builder().sodium(10).carbo(15).
fat(5).build();

Intellij IDEA에서 내부 빌더를 생성하려면 다음 플러그인을 확인하십시오.https://github.com/analytically/innerbuilder

정적인 방법으로 비정적 클래스에 액세스하려고 합니다.바꾸다Builder로.static class Builder효과가 있을 거야

다음 인스턴스가 없기 때문에 제공된 사용 예제가 실패합니다.Builder현재의.모든 실용적인 목적을 위한 스태틱클래스는 항상 인스턴스화 됩니다.정지하지 않으면 다음과 같이 말할 필요가 있습니다.

Widget = new Widget.Builder(10).setparm1(1).setparm2(3).build();

왜냐하면 당신은 새로운 시스템을 구축해야 하기 때문입니다.Builder매번.

다음 사항을 선언해야 합니다.Builder로서의 내적 계급static.

비 스태틱 내부 클래스와 스태틱 내부 클래스 모두에 대해서는, 메뉴얼을 참조해 주세요.

기본적으로 외부 클래스 인스턴스가 연결되어 있지 않으면 비 스태틱 내부 클래스 인스턴스가 존재할 수 없습니다.

아이디어가 떠올랐을 때 실제로 롬복네를 찾을 수 있을 것이다.@Builder훨씬 편리합니다.

@Builder하면 다음과 같은로 클래스를 할 수 있습니다.

Person.builder()
  .name("Adam Savage")
  .city("San Francisco")
  .job("Mythbusters")
  .job("Unchained Reaction")
 .build(); 

공식 문서: https://www.projectlombok.org/features/Builder

즉, 포위 유형을 작성할 수 없습니다.즉, 먼저 "부모" 클래스의 인스턴스를 생성한 다음 이 인스턴스에서 중첩된 클래스 인스턴스를 만들 수 있습니다.

NutritionalFacts n = new NutritionalFacts()

Builder b = new n.Builder(10).carbo(23).fat(1).build();

네스트된 클래스

Builder 클래스는 정적이어야 합니다.지금은 그 이상의 코드를 테스트할 시간이 없습니다만, 동작하지 않는 경우는 알려 주세요.다시 한 번 확인해 보겠습니다.

저는 개인적으로 두 개의 다른 클래스가 있을 때 다른 방법을 사용하는 것을 선호합니다.따라서 정적 클래스는 필요하지 않습니다.으로는 쓰지 .Class.Builder새 인스턴스를 생성해야 할 때 사용합니다.

public class Person {
    private String attr1;
    private String attr2;
    private String attr3;

    // package access
    Person(PersonBuilder builder) {
        this.attr1 = builder.getAttr1();
        // ...
    }

    // ...
    // getters and setters 
}

public class PersonBuilder (
    private String attr1;
    private String attr2;
    private String attr3;

    // constructor with required attribute
    public PersonBuilder(String attr1) {
        this.attr1 = attr1;
    }

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

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

    public Person build() {
        return new Person(this);
    }
    // ....
}

따라서 빌더를 다음과 같이 사용할 수 있습니다.

Person person = new PersonBuilder("attr1")
                            .setAttr2("attr2")
                            .build();

이는 '수업'이나 '수업'을 .static추가 없이 . 작은 추가만 가능합니다.정적 추가 없이 조금 다른 방법을 사용할 수 있습니다.

생각해 보세요.는 건축업자를 합니다.withProperty(value)클래스 내에 세터를 입력하고 참조를 반환하도록 합니다.이 접근방식에서는 스레드 세이프하고 간결한 싱글클래스와 우아한 클래스가 있습니다.

다음 사항을 고려하십시오.

public class DataObject {

    private String first;
    private String second;
    private String third;

    public String getFirst(){
       return first; 
    }

    public void setFirst(String first){
       this.first = first; 
    }

    ... 

    public DataObject withFirst(String first){
       this.first = first;
       return this; 
    }

    public DataObject withSecond(String second){
       this.second = second;
       return this; 
    }

    public DataObject withThird(String third){
       this.third = third;
       return this; 
    }
}


DataObject dataObject = new DataObject()
     .withFirst("first data")
     .withSecond("second data")
     .withThird("third data");

자세한 Java Builder 예는 여기를 참조하십시오.

Builder 클래스를 정적 클래스 Builder로 변경해야 합니다.그러면 잘 될 거예요.

다른 솔루션은 개체를 인스턴스화하기 위해 메모리 할당을 두 배로 늘립니다.다음 솔루션에는 해당 문제가 없습니다.

public class NutritionalFacts{

    private int sodium;
    private int fat;
    private int carbo;

    private NutritionalFacts(){}

    public int getSodium(){ return sodium;}

    public int getFat(){ return fat;}

    public int getCarbo(){ return carbo;}

    public static class Builder{
        private NutritionalFacts nutrionalFacts;

        public Builder(){
           nutrionalFacts = new NutritionalFacts();
        }

        public Builder sodium(int s){
            nutrionalFacts.sodium = s;
            return this;
        }

        public Builder fat(int f){
            nutrionalFacts.fat = f;
            return this;
        }

        public Builder carbo(int c){
            nutrionalFacts.carbo = c;
            return this;
        }

        public NutritionalFacts build(){
            return nutrionalFacts;
        }
    }
}

언급URL : https://stackoverflow.com/questions/5007355/builder-pattern-in-effective-java