2012-07-07 6 views
21

मेरे पास कई क्षेत्रों के साथ एक जावा कक्षा है। उन्हें मूल रूप से कन्स्ट्रक्टर चरण में सेट किया जाना चाहिए और कभी नहीं बदलना चाहिए। अर्थात् कक्षा तब एक अपरिवर्तनीय है।डिफ़ॉल्ट मान वाले कई फ़ील्ड के साथ "अपरिवर्तनीय वर्ग" का जावा कन्स्ट्रक्टर?

public class A{ 
    final int a; 
    final short b; 
    final double e; 
    final String f; 
    final String g; 
    //and more 
} 

समस्या यह है कि सामान्य रूप से इन क्षेत्रों डिफ़ॉल्ट मान है और इसलिए मैं उन सभी के साथ एक निर्माता के साथ हमेशा बोझ करने के लिए उपयोगकर्ता नहीं करना चाहती है। ज्यादातर समय, उन्हें बस उनमें से कुछ सेट करने की आवश्यकता होती है। इसे हल करने के कुछ तरीके हैं:

  1. मुझे विभिन्न हस्ताक्षर के साथ बहुत सारे कन्स्ट्रक्टर की आवश्यकता होगी।
  2. इन फ़ील्ड की सेट विधि का एक समूह बनाएं और केवल उन गैर-डिफ़ॉल्ट मान सेट करें। लेकिन यह किसी भी तरह अपरिवर्तनीय प्रकृति के अलावा एक अलग अर्थशास्त्र इंगित करता है।
  3. एक नया पैरामीटर वर्ग बनाएं जो उत्परिवर्तनीय है और उस वर्ग को कन्स्ट्रक्टर के रूप में उपयोग करें।

इनमें से कोई भी पूरी तरह से संतोषजनक नहीं है। क्या कोई और दृष्टिकोण है? धन्यवाद। एक तरह से

उत्तर

27

मैं पैरामीटर बनाने के लिए एक पैरामीटर वर्ग का एक संयोजन है और एक धाराप्रवाह बिल्डर एपीआई का प्रयोग करेंगे (तुम वैसे भी करना चाहिए जो!):

public class A { 
    private final int a; 
    private final short b; 
    private final double e; 
    private final String g; 

    public static class Aparam { 
     private int a = 1; 
     private short b = 2; 
     private double e = 3.141593; 
     private String g = "NONE"; 

     public Aparam a(int a) { 
      this.a = a; 
      return this; 
     } 

     public Aparam b(short b) { 
      this.b = b; 
      return this; 
     } 

     public Aparam e(double e) { 
      this.e = e; 
      return this; 
     } 

     public Aparam g(String g) { 
      this.g = g; 
      return this; 
     } 

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

    public static Aparam a(int a) { 
     return new Aparam().a(a); 
    } 

    public static Aparam b(short b) { 
     return new Aparam().b(b); 
    } 

    public static Aparam e(double e) { 
     return new Aparam().e(e); 
    } 

    public static Aparam g(String g) { 
     return new Aparam().g(g); 
    } 

    public static A build() { 
     return new Aparam().build(); 
    } 

    private A(Aparam p) { 
     this.a = p.a; 
     this.b = p.b; 
     this.e = p.e; 
     this.g = p.g; 
    } 

    @Override public String toString() { 
     return "{a=" + a + ",b=" + b + ",e=" + e + ",g=" + g + "}"; 
    } 
} 

फिर बनाने इस तरह एक के उदाहरण:

A a1 = A.build(); 
A a2 = A.a(7).e(17.5).build(); 
A a3 = A.b((short)42).e(2.218282).g("fluent").build(); 

क्लास ए अपरिवर्तनीय है, पैरामीटर वैकल्पिक हैं, और इंटरफेस धाराप्रवाह है।

+1

आपको अपने निर्माता में गेटर्स की भी आवश्यकता नहीं है, और ए का कन्स्ट्रक्टर निजी हो सकता है। यह कन्स्ट्रक्टर के बजाय बिल्ड() विधि में पैरामीटर की जांच करने की अनुमति देता है। –

+0

सच है। मैंने ए के सीटीआर निजी बनाने पर विचार किया। यह शायद क्लीनर है। –

+0

एक और फायदा यह है कि निर्माता पैरामीटर के आधार पर ए, एबीस या एटीर (एबीएस और एटर ए के उप-वर्ग होने का एक उदाहरण वापस करने का विकल्प चुन सकता है। –

19

दो बातें आप कर सकते हैं:

  • कई निर्माता overloads
  • उपयोग एक builder object
+4

+1। –

+0

मुझे नहीं लगता कि बिल्डर पैटर्न एक अपरिवर्तनीय वर्ग के लिए उचित है। – zggame

+0

@zggame: बिलकुल नहीं! आप किसी अन्य ऑब्जेक्ट को बनाने के लिए बिल्डर का उपयोग करते हैं। –

0

एक दिलचस्प विकल्प एक निर्माता है कि इनपुट जिसमें के रूप में एक Map<String,Object> लेता है बनाने के लिए है वे मान जिन्हें उपयोगकर्ता निर्दिष्ट करना चाहते हैं।

कन्स्ट्रक्टर मानचित्र में प्रदत्त मान का उपयोग कर सकता है यदि वर्तमान में, या डिफ़ॉल्ट मान अन्यथा हो।

संपादित करें:

मुझे लगता है कि यादृच्छिक downvoters पूरी तरह से बिंदु चूक गए - यह हमेशा सबसे अच्छा विकल्प होने जा रहा नहीं है लेकिन यह कई फायदे हैं कि एक तकनीक यह है:

  • यह संक्षिप्त है और अलग कन्स्ट्रक्टर/बिल्डर वर्ग बनाने की आवश्यकता से बचाता है
  • यह पैरामीटर सेट के आसान प्रोग्रामेटिक निर्माण की अनुमति देता है (उदाहरण के लिए यदि आप एक पार्स किए गए डीएसएल से ऑब्जेक्ट्स बना रहे हैं)
  • यह एक ऐसी तकनीक है जिसका प्रयोग अक्सर गतिशील भाषाओं में काम करने के लिए किया जाता है और साबित होता है। तुम बस सभ्य परीक्षण लिखने की ज़रूरत
+1

इससे मुख्य रूप से टाइप संगतता के साथ कई त्रुटियां होती हैं, मैं कहूंगा कि इस मामले में एक निर्माता दृष्टिकोण बेहतर होगा (जैसा कि जॉर्डो द्वारा सुझाया गया है) –

+0

वैसे यह गतिशील भाषाओं से एक तकनीक है .... आप स्थिर प्रकार की जांच कर रहे हैं सुविधा/लचीलापन। यदि आप दृष्टिकोण पसंद करते हैं तो आप पर निर्भर करता है, लेकिन मुझे लगता है कि यदि आप अच्छे परीक्षण लिखते हैं तो यह कोई समस्या नहीं है। – mikera

+0

यह जावास्क्रिप्ट तरीका है, और गतिशील टाइपिंग वाली भाषाओं में अच्छा है, लेकिन मैं इसे जावा में नहीं करूँगा। काम कर सकता है अगर सभी तर्क एक ही प्रकार के थे। फिर भी, मुझे लगता है कि बॉब मार्टिन के पास "अच्छा हैश नक्शा पास करने" के बारे में कुछ कहना अच्छा नहीं है।न तो -1 या +1। –

0

कई फ़ील्ड होने का संकेत यह हो सकता है कि एक वर्ग बहुत अधिक करता है।

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

1

यह केवल एक अर्द्ध गंभीर सुझाव है, लेकिन हम mikera's answer को टाइपएफ़ होने के लिए संशोधित कर सकते हैं।

कहो हमने:

public class A { 
    private final String foo; 
    private final int bar; 
    private final Date baz; 
} 

फिर हम लिखना:

public abstract class AProperty<T> { 
    public static final AProperty<String> FOO = new AProperty<String>(String.class) {}; 
    public static final AProperty<Integer> BAR = new AProperty<Integer>(Integer.class) {}; 
    public static final AProperty<Date> BAZ = new AProperty<Date>(Date.class) {}; 

    public final Class<T> propertyClass; 

    private AProperty(Class<T> propertyClass) { 
     this.propertyClass = propertyClass; 
    } 
} 

और:

public class APropertyMap { 
    private final Map<AProperty<?>, Object> properties = new HashMap<AProperty<?>, Object>(); 

    public <T> void put(AProperty<T> property, T value) { 
     properties.put(property, value); 
    } 
    public <T> T get(AProperty<T> property) { 
     return property.propertyClass.cast(properties.get(property)); 
    } 
} 

उन्नत डिजाइन पैटर्न और/या अस्पष्ट जावा चाल के रूप में इस पहचान लेगा की-पीने के शौकीन एक टाइपफेफ विषम कंटेनर। बस आभारी रहें मैंने getGenericSuperclass() का भी उपयोग नहीं किया।

फिर, लक्ष्य कक्षा में वापस:

public A(APropertyMap properties) { 
    foo = properties.get(AProperty.FOO); 
    bar = properties.get(AProperty.BAR); 
    baz = properties.get(AProperty.BAZ); 
} 

यह सब इस तरह प्रयोग किया जाता है:

APropertyMap properties = new APropertyMap(); 
properties.put(AProperty.FOO, "skidoo"); 
properties.put(AProperty.BAR, 23); 
A a = new A(properties); 

बस lulz के लिए, हम भी नक्शा एक धाराप्रवाह इंटरफ़ेस दे सकते हैं:

public <T> APropertyMap with(AProperty<T> property, T value) { 
    put(property, value); 
    return this; 
} 

जो कॉलर्स लिखते हैं:

A a = new A(new APropertyMap() 
    .with(AProperty.FOO, "skidoo") 
    .with(AProperty.BAR, 23)); 

इसमें बहुत कम सुधार हैं जो आप कर सकते हैं। AProperty में प्रकारों को अधिक सुंदर ढंग से संभाला जा सकता है। APropertyMap में एक कन्स्ट्रक्टर के बजाए एक स्थिर कारखाना हो सकता है, जिससे आप कोड की अधिक धाराप्रवाह शैली की अनुमति दे सकते हैं, अगर आप उस तरह की चीज में हैं। APropertyMapbuild विधि विकसित कर सकता है जो A के कन्स्ट्रक्टर को कॉल करता है, अनिवार्य रूप से इसे एक निर्माता में बदल देता है।

आप इनमें से कुछ वस्तुओं को और अधिक सामान्य बना सकते हैं। AProperty और APropertyMap में जेनेरिक बेस क्लास हो सकते हैं जो कार्यात्मक बिट्स करते थे, बहुत सरल A-विशिष्ट उप-वर्गों के साथ।

यदि आप विशेष रूप से उद्यम महसूस कर रहे हैं, और आपकी डोमेन ऑब्जेक्ट्स जेपीए 2 इकाइयां थीं, तो आप संपत्ति वस्तुओं के रूप में मेटामोडेल विशेषताओं का उपयोग कर सकते हैं। यह नक्शा/निर्माता कुछ और काम कर देता है, लेकिन यह अभी भी बहुत आसान है; मेरे पास एक सामान्य बिल्डर है जो 45 लाइनों में काम करता है, जिसमें एक इकाई के उप-वर्ग के साथ एक एकल लाइन विधि होती है। बिल्डर के लिए

+0

अच्छा। मुझे स्थिर टाइपिंग पसंद है। अच्छा समझौता, मैं इसे किसी अन्य मामले के लिए उपयोग करने में सक्षम हो सकता हूं जहां हमारे पास एक विशाल नक्शा <स्ट्रिंग, ऑब्जेक्ट> है। धन्यवाद। – zggame

संबंधित मुद्दे