प्रभावी जावा में बिल्डर पैटर्न


137

मैंने हाल ही में यहोशू बलोच द्वारा प्रभावी जावा पढ़ना शुरू किया है। मुझे बिल्डर पैटर्न [पुस्तक में आइटम 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();
    }
}

मुझे निम्नलिखित संकलक त्रुटि मिल रही है:

एक एन्क्लोज़िंग उदाहरण जिसमें प्रभावीजैवा होता है। BuilderPattern.NutitionalFacts.Builder के लिए आवश्यक है NutritFacts n = new NutritionFacts.Builder (10) .carbo (23) .fat (1) .build ()।

मुझे समझ नहीं आ रहा है कि संदेश का क्या मतलब है। कृपया समझाएँ। उपरोक्त कोड बलोच द्वारा उनकी पुस्तक में सुझाए गए उदाहरण के समान है।


जवाबों:


171

बिल्डर को staticक्लास बनाओ । तब यह काम करेगा। यदि यह गैर-स्थैतिक है, तो उसे अपने स्वयं के वर्ग के एक उदाहरण की आवश्यकता होगी - और यह बिंदु उसके पास का उदाहरण नहीं है, और यहां तक ​​कि बिल्डर के बिना उदाहरण के लिए मना करने के लिए भी।

public class NutritionFacts {
    public static class Builder {
    }
}

संदर्भ: नेस्टेड कक्षाएं


34
और, वास्तव में, Builderहै staticपुस्तक (पेज 14, 2 संस्करण में लाइन 10) में उदाहरण में।
पॉवरलॉर्ड

27

आपको बिल्डर वर्ग को स्थिर बनाना चाहिए और साथ ही आपको फ़ील्ड को अंतिम बनाना चाहिए और उन मानों को प्राप्त करने के लिए गेटर्स होना चाहिए। उन मूल्यों के लिए बसने प्रदान न करें। इस तरह आपकी कक्षा पूरी तरह से अपरिवर्तनीय हो जाएगी।

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();

सिर्फ न्यूट्रीफैक्शंस फील्ड्स को सार्वजनिक क्यों नहीं किया जाता? वे पहले से ही अंतिम हैं, और यह अभी भी अपरिवर्तनीय होगा।
skia.heliou

finalफ़ील्ड्स केवल तभी समझ में आते हैं जब खेतों को हमेशा आरंभीकरण के दौरान आवश्यक हो। यदि नहीं, तो फ़ील्ड नहीं होना चाहिए final
पियोट्रेक हिरिसुक

12

आप एक स्थिर तरीके से एक गैर-स्थिर वर्ग तक पहुंचने का प्रयास कर रहे हैं। बदलने के Builderलिए static class Builderऔर यह काम करना चाहिए।

आपके द्वारा दिया गया उदाहरण उपयोग विफल रहता है क्योंकि Builderवर्तमान का कोई उदाहरण नहीं है । सभी व्यावहारिक उद्देश्यों के लिए एक स्थिर वर्ग हमेशा तात्कालिक होता है। यदि आप इसे स्थिर नहीं बनाते हैं, तो आपको यह कहना होगा:

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

क्योंकि आपको Builderहर बार एक नए निर्माण की आवश्यकता होगी ।


12

Intellij IDEA में एक आंतरिक बिल्डर उत्पन्न करने के लिए, इस प्लगइन को देखें: https://github.com/analytically/innerbuilder


2
इससे पूछे गए सवाल से कोई लेना देना नहीं है लेकिन बहुत मददगार है! अच्छा लगा!
भूखा Androider

8

आपको Builderभीतर के वर्ग को घोषित करने की आवश्यकता है static

दोनों गैर-स्थिर आंतरिक वर्गों और स्थिर आंतरिक वर्गों के लिए कुछ प्रलेखन से परामर्श करें ।

मूल रूप से गैर-स्थिर आंतरिक वर्ग उदाहरण संलग्न बाहरी वर्ग उदाहरण के बिना मौजूद नहीं हो सकते।


5

एक बार जब आप एक विचार प्राप्त कर लेते हैं, तो व्यवहार में, आपको लुम्बोक @Builderबहुत अधिक सुविधाजनक लग सकता है।

@Builder आपको अपने कोड को कोड के साथ तत्काल रखने के लिए आवश्यक कोड का उत्पादन स्वचालित रूप से करने देता है:

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

आधिकारिक दस्तावेज: https://www.projectlombok.org/features/Builder


4

इसका मतलब यह है कि आप संलग्न प्रकार नहीं बना सकते। इसका मतलब है कि पहले आपको "पैरेंट" क्लास का एक उदाहरण देना होगा और फिर इस उदाहरण से आप नेस्टेड क्लास इंस्टेंस बना सकते हैं।

NutritionalFacts n = new NutritionalFacts()

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

नेस्टेड क्लासेस


3
इससे बहुत मतलब नहीं है, क्योंकि उसे बिल्डर को "तथ्यों" का निर्माण करने की आवश्यकता है, न कि दूसरे तरीके से।
बूझो

5
सच है अगर हम बिल्डर पैटर्न पर ध्यान केंद्रित करते हैं, तो मैंने केवल "मैं यह नहीं समझता कि संदेश का अर्थ क्या है" पर ध्यान केंद्रित किया, और दो में से एक समाधान प्रस्तुत किया।
डेमियन लेस्ज़्ज़स्की - वश

3

बिल्डर वर्ग स्थिर होना चाहिए। मेरे पास अभी समय नहीं है कि वास्तव में उस से परे कोड का परीक्षण कर सकूं, लेकिन अगर यह काम नहीं करता है तो मुझे बताएं और मैं एक और नज़र डालूंगा।


1

मैं व्यक्तिगत रूप से अन्य दृष्टिकोण का उपयोग करना पसंद करता हूं, जब आपके पास 2 अलग-अलग कक्षाएं होती हैं। इसलिए आपको किसी स्थिर वर्ग की आवश्यकता नहीं है। यह मूल रूप से लिखने से बचने के लिए है 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();

0

जैसा कि पहले से ही यहां बताया गया है कि आपको कक्षा बनाने की आवश्यकता है 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");

अधिक जावा बिल्डर उदाहरणों के लिए इसे देखें ।


0

आपको बिल्डर क्लास को स्टेटिक क्लास बिल्डर में बदलने की आवश्यकता है । फिर ठीक चलेगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.