जावा में नामित पैरामीटर मुहावरा


81

जावा में नामित पैरामीटर मुहावरे को कैसे लागू किया जाए? (विशेष रूप से निर्माणकर्ताओं के लिए)

मैं सिंटैक्स की तरह एक ऑब्जेक्टिव-सी की तलाश कर रहा हूं और JavaBeans में इस्तेमाल किए गए एक जैसे नहीं।

एक छोटा कोड उदाहरण ठीक होगा।

धन्यवाद।

जवाबों:


105

सबसे अच्छा जावा मुहावरा मैं निर्माण में खोजशब्द तर्कों का अनुकरण करने के लिए लगता है कि बिल्डर पैटर्न, प्रभावी जावा 2 संस्करण में वर्णित है

मूल विचार एक बिल्डर वर्ग के पास है जो विभिन्न निर्माण मापदंडों के लिए बसने वाले (लेकिन आमतौर पर गेटर्स नहीं है) है। इसका भी एक build()तरीका है। बिल्डर क्लास अक्सर क्लास का एक (स्टैटिक) नेस्टेड क्लास होता है जिसका निर्माण करने के लिए उपयोग किया जाता है। बाहरी वर्ग का निर्माण प्रायः निजी होता है।

अंतिम परिणाम कुछ इस तरह दिखता है:

public class Foo {
  public static class Builder {
    public Foo build() {
      return new Foo(this);
    }

    public Builder setSize(int size) {
      this.size = size;
      return this;
    }

    public Builder setColor(Color color) {
      this.color = color;
      return this;
    }

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

    // you can set defaults for these here
    private int size;
    private Color color;
    private String name;
  }

  public static Builder builder() {
      return new Builder();
  }

  private Foo(Builder builder) {
    size = builder.size;
    color = builder.color;
    name = builder.name;
  }

  private final int size;
  private final Color color;
  private final String name;

  // The rest of Foo goes here...
}

फू की एक मिसाल बनाने के लिए आप कुछ इस तरह लिखें:

Foo foo = Foo.builder()
    .setColor(red)
    .setName("Fred")
    .setSize(42)
    .build();

मुख्य चेतावनी हैं:

  1. पैटर्न सेट करना बहुत क्रिया है (जैसा कि आप देख सकते हैं)। संभवत: इसके लायक नहीं है, कक्षाओं के अलावा आप कई स्थानों पर तत्काल की योजना बनाते हैं।
  2. कोई संकलन-समय की जाँच नहीं है कि सभी मापदंडों को एक बार बिल्कुल निर्दिष्ट किया गया है। आप रनटाइम चेक जोड़ सकते हैं, या आप इसे केवल वैकल्पिक मापदंडों के लिए उपयोग कर सकते हैं और फू या बिल्डर के निर्माता के लिए आवश्यक पैरामीटर सामान्य पैरामीटर बना सकते हैं। (लोग आमतौर पर उस मामले के बारे में चिंता नहीं करते हैं जहाँ एक ही पैरामीटर को कई बार सेट किया जा रहा है।)

आप इस ब्लॉग पोस्ट को देखना चाहते हैं (मेरे द्वारा नहीं)।


12
जिस तरह से Objective-C उन्हें करता है, वैसा वास्तव में मापदंडों का नाम नहीं है। यह एक धाराप्रवाह इंटरफ़ेस की तरह दिखता है। यह वास्तव में एक ही बात नहीं है।
असफ

30
मैं का उपयोग कर की तरह है .withFoo, बजाय .setFoo: newBuilder().withSize(1).withName(1).build()के बजायnewBuilder().setSize(1).setName(1).build()
notnoop

17
Asaph: हाँ, मुझे पता है। जावा का नाम पैरामीटर नहीं है। इसलिए मैंने कहा कि यह "सबसे अच्छा जावा मुहावरा है जो मैंने खोजशब्द तर्क के अनुकरण के लिए देखा है"। ऑब्जेक्टिव-सी के "नामित पैरामीटर" भी आदर्श से कम हैं, क्योंकि वे एक विशेष आदेश देने के लिए मजबूर करते हैं। वे लिस्प या पाइथन की तरह सच्चे खोजशब्द तर्क नहीं हैं। कम से कम जावा बिल्डर पैटर्न के साथ आपको केवल वास्तविक कीवर्ड तर्क की तरह, नामों को याद रखने की आवश्यकता है, न कि आदेश की।
लॉरेंस गोंसाल्वेस

14
notnoop: मुझे "सेट" पसंद है क्योंकि ये बिल्डर की स्थिति को बदलने वाले सेटर हैं। हां, "के साथ" साधारण मामले में अच्छा लगता है जहां आप सब कुछ एक साथ कर रहे हैं, लेकिन अधिक जटिल मामलों में जहां आपको बिल्डर को अपने चर में मिला है (शायद इसलिए कि आप सशर्त रूप से गुण सेट कर रहे हैं) मुझे वह सेट पसंद है उपसर्ग यह पूरी तरह से स्पष्ट करता है कि बिल्डर को इन तरीकों से बुलाया जाने पर उत्परिवर्तित किया जा रहा है। "के साथ" उपसर्ग मेरे लिए कार्यात्मक लगता है, और ये तरीके निश्चित रूप से कार्यात्मक नहीं हैं।
लॉरेंस गोंसाल्वेस 6

4
There's no compile-time checking that all of the parameters have been specified exactly once.इस समस्या को वहाँ लौटने वाले इंटरफेस Builder1से दूर किया जा सकता है, BuilderNजहाँ प्रत्येक व्यक्ति बसने वालों में से एक को कवर करता है या build()। यह कोड के लिए बहुत अधिक क्रिया है, लेकिन यह आपके डीएसएल के लिए संकलक समर्थन के साथ आता है और साथ काम करने के लिए ऑटो-पूर्ण बहुत अच्छा बनाता है।
आरपी

73

यह उल्लेख के लायक है:

Foo foo = new Foo() {{
    color = red;
    name = "Fred";
    size = 42;
}};

तथाकथित डबल-ब्रेस इनिशियलाइज़र । यह वास्तव में उदाहरण के साथ एक प्रारंभिक वर्ग है initializer।


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

6
ऑटो-फॉर्मेटिंग, सबक्लासिंग और सीरियललाइज़ेशन को एक तरफ से चेतावनी देता है, यह वास्तव में प्रॉपर्टी-बेस्ड इनिशियलाइज़ेशन के लिए C # सिंटैक्स के काफी करीब है। हालाँकि, 4.0 के रूप में C # ने भी मापदंडों का नाम दिया है, इसलिए प्रोग्रामर वास्तव में पसंद के लिए खराब हो जाते हैं, जावा प्रोग्रामर के विपरीत जो मुहावरों का अनुकरण करना है जो उन्हें बाद में पैर में खुद को गोली मारने से रोकते हैं।
डिस्टॉर्टम

3
यह देखने के लिए खुशी संभव है लेकिन मुझे नीचे उतरना पड़ा क्योंकि यह समाधान महंगा है क्योंकि रेड हाइना ने बताया। तब तक इंतजार नहीं किया जा सकता जब तक कि जावा वास्तव में नामित मापदंडों का समर्थन नहीं करता है जैसे कि पायथन करता है।
गैटस्टर

12
वोट दें। यह सबसे पठनीय, संक्षिप्त तरीके से प्रश्न का उत्तर देता है। ठीक। यह "प्रदर्शन नहीं" है। हम यहां कितने अतिरिक्त मिलीसेकंड और बिट्स बात कर रहे हैं? उनमें से लोग? दसियों? ; मुझे गलत मत - मैं इस का उपयोग कर नहीं किया जाएगा के रूप में मैं जावा अखरोट वर्बोज़ एक द्वारा निष्पादित की जाने नफरत चाहते हैं (यमक इरादा)
स्टीव

2
उत्तम! केवल सार्वजनिक / संरक्षित क्षेत्रों की आवश्यकता है। यह निश्चित रूप से सबसे अच्छा समाधान है, जिससे बिल्डर की तुलना में बहुत कम ओवरहेड होता है। हाइना / गैटस्टर: कृपया (1) अपनी टिप्पणियों को लिखने से पहले जेएलएस और (2) जेनरेट किए गए बायटेकोड की जांच करें।
जोनातन कामीरेसक

21

आप यहां से सलाह का पालन करने की कोशिश कर सकते हैं: http://www.artima.com/weblogs/viewpost.jsp?thread/118828

int value; int location; boolean overwrite;
doIt(value=13, location=47, overwrite=true);

यह कॉल साइट पर क्रिया है, लेकिन कुल मिलाकर सबसे कम ओवरहेड देता है।


3
कम ओवरहेड का अच्छा कारण है, लेकिन ऐसा लगता है कि हैक किया गया है। मैं शायद उन मामलों के लिए बिल्डर () पद्धति का उपयोग करने जा रहा हूं जहां कई तर्क हैं।
गैटस्टर

23
मुझे लगता है कि यह पूरी तरह से नामित मापदंडों के बिंदु को याद करता है। (जिसमें मूल्यों के साथ कुछ सहयोगी नाम हैं )। यदि आप आदेश को उलटते हैं तो कोई संकेत नहीं है । ऐसा करने के बजाय मैं बस एक टिप्पणी जोड़ने की सलाह doIt( /*value*/ 13, /*location*/ 47, /*overwrite*/ true )
दूंगा

20

जावा 8 शैली:

public class Person {
    String name;
    int age;

    private Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    static PersonWaitingForName create() {
        return name -> age -> new Person(name, age);
    }

    static interface PersonWaitingForName {
        PersonWaitingForAge name(String name);
    }

    static interface PersonWaitingForAge {
        Person age(int age);
    }

    public static void main(String[] args) {

        Person charlotte = Person.create()
            .name("Charlotte")
            .age(25);

    }
}
  • नामित पैरामीटर
  • तर्कों का क्रम तय करें
  • स्थैतिक जाँच -> कोई भी व्यक्ति संभव नहीं
  • एक ही प्रकार के तर्कों को दुर्घटना से बदलना मुश्किल है (जैसे कि दूरबीन निर्माणकर्ताओं में यह संभव है)

3
अच्छा है। क्या एक किटी है यह चर तर्क आदेश नहीं है। (लेकिन यह कहने के लिए नहीं कि मैं इसका इस्तेमाल करूंगा ...)
शीथिनोड

1
यह एक शानदार विचार है। की परिभाषा create()मुझे मेरे पटरियों में बंद कर दिया। मैंने जावा में लैम्बडा की शैली को कभी नहीं देखा है। क्या आपने पहली बार लैम्बदास के साथ दूसरी भाषा में इस विचार की खोज की थी?
केविनरपे

2
इसे क्यूरिंग कहा जाता है: en.wikipedia.org/wiki/Currying । Btw: शायद यह एक चतुर विचार है, लेकिन मैं इस नाम तर्क शैली को पुनः शामिल नहीं करूंगा। मैंने कई तर्कों के साथ एक वास्तविक परियोजना में इसका परीक्षण किया और इसे पढ़ने के लिए कठिन और कोड नेविगेट करने में मुश्किल होती है।
एलेक्स

आखिरकार, जावा को विजुअल बेसिक स्टाइल नाम दिया जाएगा। जावा पहले नहीं था क्योंकि C ++ नहीं है। लेकिन हम अंततः वहां पहुंचेंगे। मैं कहूंगा कि जावा पॉलिमॉर्फिज्म का 90% सिर्फ वैकल्पिक मापदंडों के आसपास हैकिंग है।
Tuntable

7

जावा कंस्ट्रक्टर या विधि तर्कों के लिए उद्देश्य-सी-जैसे नामित मापदंडों का समर्थन नहीं करता है। इसके अलावा, यह वास्तव में चीजों को करने का जावा तरीका नहीं है। जावा में, विशिष्ट पैटर्न को मौखिक रूप से कक्षाओं और सदस्यों का नाम दिया गया है। कक्षाएं और चर संज्ञाएं होनी चाहिए और नाम वाली विधि क्रियाएं होनी चाहिए। मुझे लगता है कि आप रचनात्मक हो सकते हैं और जावा नामकरण सम्मेलनों से विचलित हो सकते हैं और एक हैक तरीके से ऑब्जेक्टिव-सी प्रतिमान का अनुकरण कर सकते हैं, लेकिन यह आपके कोड को बनाए रखने के साथ चार्ज किए गए औसत जावा डेवलपर द्वारा विशेष रूप से सराहना नहीं की जाएगी। किसी भी भाषा में काम करते समय, यह आपको भाषा और समुदाय के सम्मेलनों से चिपके रहने के लिए प्रेरित करता है, खासकर जब एक टीम पर काम कर रहा हो।


4
+1 - उस भाषा के मुहावरों से चिपके रहने के बारे में सलाह के लिए जो आप वर्तमान में उपयोग कर रहे हैं। कृपया उन अन्य लोगों के बारे में सोचें जिन्हें आपके कोड को पढ़ने की आवश्यकता होगी!
स्टीफन सी

3
मैंने आपके उत्तर को गलत ठहराया क्योंकि मुझे लगता है कि आप एक अच्छा बिंदु बनाते हैं। अगर मुझे यह अनुमान लगाना होता है कि आपको नीचा क्यों मिला, तो शायद यह है क्योंकि यह सवाल का जवाब नहीं देता है। प्रश्न: "मैं जावा में मानकों का नाम कैसे दूं?" उ: "आप नहीं"
गैटस्टर

12
मैं नीचा दिखाती हूं क्योंकि मुझे लगता है कि आपके जवाब का सवाल से कोई लेना-देना नहीं है। शब्दशः नाम वास्तव में पैरामीटर ऑर्डरिंग की समस्या को हल नहीं करते हैं। हां, आप उन्हें नाम में एन्कोड कर सकते हैं लेकिन यह स्पष्ट रूप से व्यावहारिक नहीं है। एक असंबंधित प्रतिमान लाने से यह स्पष्ट नहीं होता है कि एक प्रतिमान का समर्थन क्यों नहीं किया जाता है।
एंड्रियास म्यूएलर

7

यदि आप जावा 6 का उपयोग कर रहे हैं, तो आप चर मापदंडों का उपयोग कर सकते हैं और स्थैतिक को बेहतर परिणाम देने के लिए आयात कर सकते हैं। इसका विवरण इसमें पाया गया है:

http://zinzel.blogspot.com/2010/07/creating-methods-with-onym-parameters.html

संक्षेप में, आपके पास कुछ ऐसा हो सकता है:

go();
go(min(0));
go(min(0), max(100));
go(max(100), min(0));
go(prompt("Enter a value"), min(0), max(100));

2
मुझे यह पसंद है, लेकिन यह अभी भी केवल आधी समस्या को हल करता है। जावा में, आप आवश्यक मानों के लिए एक संकलन-समय की जांच को खोए बिना गलती से स्थानांतरित मापदंडों को रोक नहीं सकते हैं।
cdunn2001

प्रकार सुरक्षा के बिना यह सरल // टिप्पणियों से भी बदतर है।
पीटर डेविस

7

मैं कहना है कि यह शैली पतों दोनों चाहते हैं नामित पैरामीटर और गुण के बिना सुविधाओं प्राप्त और सेट उपसर्ग जो अन्य भाषा है। जावा दायरे में इसकी पारंपरिक नहीं, बल्कि इसकी सरलता, समझने में मुश्किल नहीं है, खासकर यदि आपने अन्य भाषाओं को संभाला है।

public class Person {
   String name;
   int age;

   // name property
   // getter
   public String name() { return name; }

   // setter
   public Person name(String val)  { 
    name = val;
    return this;
   }

   // age property
   // getter
   public int age() { return age; }

   // setter
   public Person age(int val) {
     age = val;
     return this;
   }

   public static void main(String[] args) {

      // Addresses named parameter

      Person jacobi = new Person().name("Jacobi").age(3);

      // Addresses property style

      println(jacobi.name());
      println(jacobi.age());

      //...

      jacobi.name("Lemuel Jacobi");
      jacobi.age(4);

      println(jacobi.name());
      println(jacobi.age());
   }
}

6

व्हाट अबाउट

public class Tiger {
String myColor;
int    myLegs;

public Tiger color(String s)
{
    myColor = s;
    return this;
}

public Tiger legs(int i)
{
    myLegs = i;
    return this;
}
}

Tiger t = new Tiger().legs(4).color("striped");

5
बिल्डर बहुत बेहतर है, क्योंकि आप बिल्ड () पर कुछ बाधाओं की जांच कर सकते हैं। लेकिन मैं सेट के साथ / उपसर्ग के बिना छोटे तर्कों को भी पसंद करता हूं।
rjj

4
साथ ही, बिल्डर पैटर्न बेहतर है क्योंकि यह आपको अंतर्निहित वर्ग (इस मामले में टाइगर) को अपरिवर्तनीय बनाने की अनुमति देता है।
जेफ ओल्सन

2

आप एक सामान्य रचनाकार और स्थिर तरीकों का उपयोग कर सकते हैं जो तर्कों को एक नाम देते हैं:

public class Something {

    String name;
    int size; 
    float weight;

    public Something(String name, int size, float weight) {
        this.name = name;
        this.size = size;
        this.weight = weight;
    }

    public static String name(String name) { 
        return name; 
    }

    public static int size(int size) {
        return size;
    }

    public float weight(float weight) {
        return weight;
    }

}

उपयोग:

import static Something.*;

Something s = new Something(name("pen"), size(20), weight(8.2));

वास्तविक नामित मापदंडों की तुलना में सीमाएं:

  • तर्क आदेश प्रासंगिक है
  • एकल निर्माता के साथ चर तर्क सूची संभव नहीं है
  • आपको हर तर्क के लिए एक विधि की आवश्यकता है
  • वास्तव में एक टिप्पणी से बेहतर नहीं (नया कुछ /*name*/ "pen", /*size*/ 20, /*weight*/ 8.2))

यदि आपके पास स्काला 2.8 का विकल्प है। http://www.scala-lang.org/node/2075


2
इस दृष्टिकोण के लिए एक नकारात्मक पक्ष यह है कि आप है चाहिए सही क्रम में तर्क मिलता है। उपरोक्त कोड आपको लिखने देगा: कुछ s = नया कुछ (नाम ("पेन"), आकार (20), आकार (21)); इसके अलावा, यह दृष्टिकोण आपको वैकल्पिक तर्कों में लिखने से बचने में मदद नहीं करता है।
मैट क्वेल

1
मैं इस विश्लेषण के लिए इसे not really better than a commentआगे
बढ़ाऊंगा

2

जावा 8 के लैम्ब्डा का उपयोग करके आप वास्तविक नामित मापदंडों के करीब भी पहुंच सकते हैं ।

foo($ -> {$.foo = -10; $.bar = "hello"; $.array = new int[]{1, 2, 3, 4};});

ध्यान दें कि यह संभवतः एक युगल दर्जन "जावा सर्वोत्तम प्रथाओं" का उल्लंघन करता है (जैसे कि कुछ भी जो $प्रतीक का उपयोग करता है )।

public class Main {
  public static void main(String[] args) {
    // Usage
    foo($ -> {$.foo = -10; $.bar = "hello"; $.array = new int[]{1, 2, 3, 4};});
    // Compare to roughly "equivalent" python call
    // foo(foo = -10, bar = "hello", array = [1, 2, 3, 4])
  }

  // Your parameter holder
  public static class $foo {
    private $foo() {}

    public int foo = 2;
    public String bar = "test";
    public int[] array = new int[]{};
  }

  // Some boilerplate logic
  public static void foo(Consumer<$foo> c) {
    $foo foo = new $foo();
    c.accept(foo);
    foo_impl(foo);
  }

  // Method with named parameters
  private static void foo_impl($foo par) {
    // Do something with your parameters
    System.out.println("foo: " + par.foo + ", bar: " + par.bar + ", array: " + Arrays.toString(par.array));
  }
}

पेशेवरों:

  • अब तक मैंने देखे गए किसी भी बिल्डर पैटर्न से काफी कम
  • दोनों तरीकों और निर्माणकर्ताओं के लिए काम करता है
  • पूरी तरह से सुरक्षित है
  • यह अन्य प्रोग्रामिंग भाषाओं में वास्तविक नामित मापदंडों के बहुत करीब दिखता है
  • यह आपके विशिष्ट बिल्डर पैटर्न जितना सुरक्षित है (कई बार पैरामीटर सेट कर सकता है)

विपक्ष:

  • आपका बॉस शायद आपको इसके लिए लिंच करेगा
  • यह बताना मुश्किल है कि क्या हो रहा है

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

बसने का उपयोग कर सकता है, लेकिन इसमें क्या बात है? यह सिर्फ कोड को लंबा बनाता है और यह इस तरह से करने के लाभ को समाप्त करेगा। असाइनमेंट साइड इफेक्ट फ्री है और बसने वाले ब्लैक बॉक्स हैं। $fooकभी भी कॉल करने वाले के पास नहीं भागता (जब तक कि कोई उसे कॉलबैक के अंदर वैरिएबल को असाइन नहीं करता) तब तक वे सार्वजनिक क्यों नहीं हो सकते ?
विक

2

जावा में नामित मापदंडों का अनुकरण करने के लिए आप प्रोजेक्ट लोनोक के @Builder एनोटेशन का उपयोग कर सकते हैं । यह आपके लिए एक बिल्डर उत्पन्न करेगा जिसका उपयोग आप किसी भी वर्ग (आपके द्वारा लिखी गई कक्षाओं और बाहरी पुस्तकालयों से आने वाले दोनों वर्गों) के नए उदाहरण बनाने के लिए कर सकते हैं।

यह एक वर्ग पर इसे सक्षम करने का तरीका है:

@Getter
@Builder
public class User {
    private final Long id;
    private final String name;
}

बाद में आप इसका उपयोग कर सकते हैं:

User userInstance = User.builder()
    .id(1L)
    .name("joe")
    .build();

यदि आप लाइब्रेरी से आने वाले वर्ग के लिए इस तरह का एक बिल्डर बनाना चाहते हैं, तो इस तरह एक एनोटेट स्टेटिक विधि बनाएं:

class UserBuilder {
    @Builder(builderMethodName = "builder")
    public static LibraryUser newLibraryUser(Long id, String name) {
        return new LibraryUser(id, name);
    }
  }

यह "बिल्डर" नामक एक विधि उत्पन्न करेगा जिसे इसके द्वारा बुलाया जा सकता है:

LibraryUser user = UserBuilder.builder()
    .id(1L)
    .name("joe")
    .build();

Google ऑटो / मूल्य एक अनुकरणीय उद्देश्य प्रदान करता है लेकिन एनोटेशन प्रोसेसिंग फ्रेमवर्क का उपयोग करता है, जो कि प्रोजेक्ट लोम्बॉक्स बाइट कोड हेरफेर की तुलना में बहुत अधिक सुरक्षित है (जेवीएम के उन्नयन के बाद भी काम करेगा)।
रेने

1
मुझे लगता है कि लोम्बोक का उपयोग करने की तुलना में Google ऑटो / मूल्य में एक अतिरिक्त मील की आवश्यकता है। लोम्बोक का दृष्टिकोण पारंपरिक जावाबीन लेखन के साथ अधिक या कम संगत है (जैसे आप नए के माध्यम से त्वरित कर सकते हैं, फ़ील्ड डीबगर में ठीक से दिखाई देते हैं, आदि)। मैं बाइट कोड मैनपिलिएशन + आईडीई प्लगइन समाधान का एक बड़ा प्रशंसक नहीं हूं जो लोम्बोक उपयोग करता है, लेकिन मुझे यह स्वीकार करना होगा कि व्यवहार में यह ठीक काम करता है। JDK संस्करण परिवर्तन, प्रतिबिंब आदि के साथ अब तक कोई समस्या नहीं है
इस्तवान देवाई

हाँ वह सच है। ऑटो / मूल्य के लिए आपको एक अमूर्त वर्ग प्रदान करना होगा जो तब लागू किया जाएगा। लोम्बोक को बहुत कम कोड की आवश्यकता है। इसलिए पेशेवरों और विपक्ष की तुलना करने की आवश्यकता है।
रेने

2

मुझे लगता है कि "टिप्पणी-वर्कअराउंड" का यह हकदार है कि यह खुद का जवाब है (मौजूदा उत्तरों में छिपा हुआ है और यहां टिप्पणियों में उल्लेख किया गया है)।

someMethod(/* width */ 1024, /* height */ 768);

1

यह एक प्रकार है Builder लॉरेंस द्वारा ऊपर वर्णित पैटर्न ।

मैं खुद को इसका इस्तेमाल करते हुए बहुत (उपयुक्त स्थानों पर) पाता हूं।

मुख्य अंतर यह है, कि इस मामले में बिल्डर अपरिवर्तनीय है । इसका फायदा यह है कि इसका पुन: उपयोग किया जा सकता है और यह थ्रेड-सुरक्षित है।

तो आप इसका उपयोग एक डिफ़ॉल्ट बिल्डर बनाने के लिए कर सकते हैं और फिर विभिन्न स्थानों पर करने के लिए कर सकते हैं जहां आपको इसकी आवश्यकता है आप इसे कॉन्फ़िगर कर सकते हैं और अपनी वस्तु का निर्माण कर सकते हैं।

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

दूसरी ओर अगर आपको बदलते पैरामाटर्स के साथ वस्तुओं का निर्माण करना है तो इससे कुछ ओवरहेड शांत हो जाता है। (लेकिन हे, आप कस्टम buildतरीकों के साथ स्थिर / गतिशील पीढ़ी को जोड़ सकते हैं )

यहाँ उदाहरण कोड है:

public class Car {

    public enum Color { white, red, green, blue, black };

    private final String brand;
    private final String name;
    private final Color color;
    private final int speed;

    private Car( CarBuilder builder ){
        this.brand = builder.brand;
        this.color = builder.color;
        this.speed = builder.speed;
        this.name = builder.name;
    }

    public static CarBuilder with() {
        return DEFAULT;
    }

    private static final CarBuilder DEFAULT = new CarBuilder(
            null, null, Color.white, 130
    );

    public static class CarBuilder {

        final String brand;
        final String name;
        final Color color;
        final int speed;

        private CarBuilder( String brand, String name, Color color, int speed ) {
            this.brand = brand;
            this.name = name;
            this.color = color;
            this.speed = speed;
        }
        public CarBuilder brand( String newBrand ) {
            return new CarBuilder( newBrand, name, color, speed );
        }
        public CarBuilder name( String newName ) {
            return new CarBuilder( brand, newName, color, speed );
        }
        public CarBuilder color( Color newColor ) {
            return new CarBuilder( brand, name, newColor, speed );
        }
        public CarBuilder speed( int newSpeed ) {
            return new CarBuilder( brand, name, color, newSpeed );
        }
        public Car build() {
            return new Car( this );
        }
    }

    public static void main( String [] args ) {

        Car porsche = Car.with()
                .brand( "Porsche" )
                .name( "Carrera" )
                .color( Color.red )
                .speed( 270 )
                .build()
                ;

        // -- or with one default builder

        CarBuilder ASSEMBLY_LINE = Car.with()
                .brand( "Jeep" )
                .name( "Cherokee" )
                .color( Color.green )
                .speed( 180 )
                ;

        for( ;; ) ASSEMBLY_LINE.build();

        // -- or with custom default builder:

        CarBuilder MERCEDES = Car.with()
                .brand( "Mercedes" )
                .color( Color.black )
                ;

        Car c230 = MERCEDES.name( "C230" ).speed( 180 ).build(),
            clk = MERCEDES.name( "CLK" ).speed( 240 ).build();

    }
}

1

जावा में कोई समाधान होने की संभावना बहुत वर्बोज़ होने जा रहा है, लेकिन यह की कीमत की तरह है कि उपकरणों का उल्लेख गूगल AutoValues और Immutables बिल्डर वर्गों आप स्वचालित रूप से JDK संकलन समय एनोटेशन प्रसंस्करण प्रयोग करने के लिए उत्पन्न होगा।

मेरे मामले के लिए, मैं एक जावा एनम में उपयोग करने के लिए पैरामीटर नामित करना चाहता था, इसलिए एक बिल्डर पैटर्न काम नहीं करेगा क्योंकि एनम इंस्टेंसेस को अन्य वर्गों द्वारा त्वरित नहीं किया जा सकता है। मैं इसी तरह के बहरे के जवाब के साथ एक दृष्टिकोण के साथ आया था, लेकिन पैरामीटर ऑर्डरिंग के संकलन-समय की जाँच को जोड़ता है (अधिक कोड की कीमत पर)

यहाँ ग्राहक कोड है:

Person p = new Person( age(16), weight(100), heightInches(65) );

और कार्यान्वयन:

class Person {
  static class TypedContainer<T> {
    T val;
    TypedContainer(T val) { this.val = val; }
  }
  static Age age(int age) { return new Age(age); }
  static class Age extends TypedContainer<Integer> {
    Age(Integer age) { super(age); }
  }
  static Weight weight(int weight) { return new Weight(weight); }
  static class Weight extends TypedContainer<Integer> {
    Weight(Integer weight) { super(weight); }
  }
  static Height heightInches(int height) { return new Height(height); }
  static class Height extends TypedContainer<Integer> {
    Height(Integer height) { super(height); }
  }

  private final int age;
  private final int weight;
  private final int height;

  Person(Age age, Weight weight, Height height) {
    this.age = age.val;
    this.weight = weight.val;
    this.height = height.val;
  }
  public int getAge() { return age; }
  public int getWeight() { return weight; }
  public int getHeight() { return height; }
}

0

करग पुस्तकालय द्वारा समर्थित मुहावरे पर विचार करने योग्य हो सकता है:

class Example {

    private static final Keyword<String> GREETING = Keyword.newKeyword();
    private static final Keyword<String> NAME = Keyword.newKeyword();

    public void greet(KeywordArgument...argArray) {
        KeywordArguments args = KeywordArguments.of(argArray);
        String greeting = GREETING.from(args, "Hello");
        String name = NAME.from(args, "World");
        System.out.println(String.format("%s, %s!", greeting, name));
    }

    public void sayHello() {
        greet();
    }

    public void sayGoodbye() {
        greet(GREETING.of("Goodbye");
    }

    public void campItUp() {
        greet(NAME.of("Sailor");
    }
}

यह मूल रूप से R Cashaउत्तर के समान है लेकिन इसे समझाने के लिए कोड के बिना है।
३५ पर शीथिनोड

0

यहां एक कंपाइलर-चेक बिल्डर पैटर्न है। कैविट्स:

  • यह एक तर्क के दोहरे असाइनमेंट को रोक नहीं सकता है
  • आपके पास एक अच्छी .build()विधि नहीं हो सकती
  • प्रति क्षेत्र एक सामान्य पैरामीटर

तो आपको कक्षा के बाहर कुछ ऐसा चाहिए जो पास न होने पर असफल हो जाए Builder<Yes, Yes, Yes>getSumउदाहरण के रूप में स्थैतिक विधि देखें ।

class No {}
class Yes {}

class Builder<K1, K2, K3> {
  int arg1, arg2, arg3;

  Builder() {}

  static Builder<No, No, No> make() {
    return new Builder<No, No, No>();
  }

  @SuppressWarnings("unchecked")
  Builder<Yes, K2, K3> arg1(int val) {
    arg1 = val;
    return (Builder<Yes, K2, K3>) this;
  }

  @SuppressWarnings("unchecked")
  Builder<K1, Yes, K3> arg2(int val) {
    arg2 = val;
    return (Builder<K1, Yes, K3>) this;
  }

  @SuppressWarnings("unchecked")
  Builder<K1, K2, Yes> arg3(int val) {
    this.arg3 = val;
    return (Builder<K1, K2, Yes>) this;
  }

  static int getSum(Builder<Yes, Yes, Yes> build) {
    return build.arg1 + build.arg2 + build.arg3;
  }

  public static void main(String[] args) {
    // Compiles!
    int v1 = getSum(make().arg1(44).arg3(22).arg2(11));
    // Builder.java:40: error: incompatible types:
    // Builder<Yes,No,Yes> cannot be converted to Builder<Yes,Yes,Yes>
    int v2 = getSum(make().arg1(44).arg3(22));
    System.out.println("Got: " + v1 + " and " + v2);
  }
}

कैविट्स ने समझाया । कोई निर्माण विधि क्यों? मुसीबत यह है कि यह Builderकक्षा में होने जा रहा है , और इसे इसके साथ मानकीकृत किया जाएगाK1, K2, K3 , आदि। जैसा कि विधि को खुद को संकलित करना है, सब कुछ इसे कॉल करना होगा। इसलिए, आम तौर पर, हम कक्षा की एक विधि में एक संकलन परीक्षा नहीं दे सकते हैं।

इसी तरह के कारण से, हम बिल्डर मॉडल का उपयोग करके दोहरे असाइनमेंट को रोक नहीं सकते हैं।


-1

@irreputable एक अच्छा समाधान लेकर आया। हालांकि - यह आपकी कक्षा को अमान्य स्थिति में छोड़ सकता है, क्योंकि कोई सत्यापन और संगतता जाँच नहीं होगी। इसलिए मैं इसे बिल्डर समाधान के साथ जोड़ना पसंद करता हूं, अतिरिक्त उपवर्ग को बनाए जाने से बचता हूं, हालांकि यह अभी भी बिल्डर वर्ग को उपवर्ग में रखेगा। इसके अतिरिक्त, क्योंकि अतिरिक्त बिल्डर वर्ग इसे और अधिक क्रियाशील बनाता है, इसलिए मैंने लैम्बडा का उपयोग करके एक और विधि जोड़ी। मैंने पूर्णता के लिए कुछ अन्य बिल्डर दृष्टिकोण जोड़े।

निम्नानुसार एक वर्ग से शुरू करना:

public class Foo {
  static public class Builder {
    public int size;
    public Color color;
    public String name;
    public Builder() { size = 0; color = Color.RED; name = null; }
    private Builder self() { return this; }

    public Builder size(int size) {this.size = size; return self();}
    public Builder color(Color color) {this.color = color; return self();}
    public Builder name(String name) {this.name = name; return self();}

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

  private final int size;
  private final Color color;
  private final String name;

  public Foo(Builder b) {
    this.size = b.size;
    this.color = b.color;
    this.name = b.name;
  }

  public Foo(java.util.function.Consumer<Builder> bc) {
    Builder b = new Builder();
    bc.accept(b);
    this.size = b.size;
    this.color = b.color;
    this.name = b.name;
  }

  static public Builder with() {
    return new Builder();
  }

  public int getSize() { return this.size; }
  public Color getColor() { return this.color; }  
  public String getName() { return this.name; }  

}

फिर इसका उपयोग विभिन्न तरीकों को लागू करने में:

Foo m1 = new Foo(
  new Foo.Builder ()
  .size(1)
  .color(BLUE)
  .name("Fred")
);

Foo m2 = new Foo.Builder()
  .size(1)
  .color(BLUE)
  .name("Fred")
  .build();

Foo m3 = Foo.with()
  .size(1)
  .color(BLUE)
  .name("Fred")
  .build();

Foo m4 = new Foo(
  new Foo.Builder() {{
    size = 1;
    color = BLUE;
    name = "Fred";
  }}
);

Foo m5 = new Foo(
  (b)->{
    b.size = 1;
    b.color = BLUE;
    b.name = "Fred";
  }
);

यह @LaurenceGonsalves पहले से ही पोस्ट किए गए भाग से कुल चीर-फाड़ की तरह दिखता है, लेकिन आपको चुने गए सम्मेलन में छोटे अंतर दिखाई देंगे।

मुझे आश्चर्य है, अगर जेएलएस कभी नामित मापदंडों को लागू करेगा, तो वे इसे कैसे करेंगे? क्या वे मौजूदा मुहावरों में से एक पर इसके लिए एक संक्षिप्त रूप प्रदान करके अपना विस्तार करेंगे? इसके अलावा स्काला कैसे नामित मापदंडों का समर्थन करता है?

हम्म - अनुसंधान के लिए पर्याप्त है, और शायद एक नया सवाल।

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