2014-09-23 6 views
6

मैं कई अलग अलग POJOs कि एक builder pattern उपयोग करें, लेकिन हर एक के लिए एक बिल्डर को जोड़ने और Object.toString, Object.hashCode और Object.equals पैदा करने के बाद, मेरे कक्षाएं खत्म कोड के करीब 100 लाइनों जा रहा है। इसे संभालने के लिए एक बेहतर तरीका होना चाहिए। मुझे लगता है कि कुछ प्रकार के प्रतिबिंबित निर्माता होने से बहुत मदद मिलेगी, लेकिन मुझे यकीन नहीं है कि यह अच्छा अभ्यास होगा और मुझे यह भी यकीन नहीं है कि मैं इसे कैसे करूँगा। दूसरे शब्दों में, क्या इस तरह के निर्माता को लागू करने का कोई तरीका है?बहुत ज्यादा बॉयलरप्लेट, मैं अपने POJO बिल्डरों को कैसे कम कर सकता हूं?

एक साधारण POJO:

public class Foo { 

    public int id; 
    public String title; 
    public boolean change; 
    ... 

} 

फिर चिंतनशील बिल्डर के कुछ प्रकार:

Foo = ReflectiveBuilder.from(Foo.class).id(1).title("title").change(false).build(); 
+0

क्या आप ToString हैशकोड के लिए अपाचे कॉमन्स का उपयोग कर रहे हैं और बराबर हैं? यह अभी भी एक दर्द है, लेकिन आपको बहुत समय बचाएगा। आपके कोड में बेस क्लास है जो प्रतिबिंबित करता है, स्ट्रिंग, बराबर और हैशकोड तब आपके सभी POJO को – Leon

+0

@Leon I do, वास्तव में प्राप्त करता है। लेकिन प्रत्येक वर्ग अभी भी प्रत्येक निर्माता से कोड की 70-100 लाइनों को समाप्त कर देगा।एक बेहतर पैटर्न होना चाहिए जिसे मैं सिर्फ एक प्रतिबिंबित निर्माता को लागू करने के लिए नहीं जानता हूं या कम से कम ऐसा महसूस करता हूं। – buildpattern

उत्तर

4

लघु जवाब कोई लेकिन ध्यान रखें कि यह एक प्रायोगिक सुविधा है। आप जो पूछते हैं वह संभव नहीं है। प्रतिबिंब रनटाइम पर कोड को देखता है और गतिशील रूप से विधियों को आमंत्रित करता है, यह वास्तविक तरीकों को उत्पन्न नहीं कर सकता है।

आप होगा कर सकता है क्या:

Foo foo = ReflectiveBuilder.from(Foo.class). 
       set("id", 1). 
       set("title", "title"). 
       build(); 

इस तीन बड़े पैमाने पर समस्या है:

  1. क्षेत्रों String रों हैं - एक टाइपो एक संकलन समय एक के बजाय एक रनटाइम त्रुटि का कारण बनता है ,
  2. मान Object एस हैं - गलत प्रकार संकलन समय के बजाय रनटाइम त्रुटि का कारण बनता है, और
  3. यह विकल्प से बहुत धीमा होगा क्योंकि प्रतिबिंब बहुत धीमा है।

तो एक प्रतिबिंब आधारित समाधान, जबकि संभव हो (अपाचे कॉमन्स बीनयूट्स BeanMap देखें) बिल्कुल व्यावहारिक नहीं है।

लंबे उत्तर, यदि आप कुछ संकलन समय जादू की अनुमति देने के इच्छुक हैं, तो आप Project Lombok का उपयोग कर सकते हैं। लंबोक के पीछे विचार जावा एनोटेशन प्रीप्रोसेसर सिस्टम का उपयोग करके एनोटेशन से बॉयलरप्लेट कोड उत्पन्न करना है।

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

एक एक Builder साथ POJO आप @Data उपयोग कर सकते हैं के मामले में और @Builder

@Data 
@Builder 
public class Foo { 

    public int id; 
    public String title; 
    public boolean change; 
    ... 

} 

@Data एनोटेशन उत्पन्न करेगा:

  • एक आवश्यक तर्क निर्माता (है कि सभी final क्षेत्रों लेता है),
  • equals और hashCode विधियां जो सभी फ़ील्ड का उपयोग करती हैं (@EqualsAndHashCode टिप्पणी के साथ विन्यस्त किया जा सकता)
  • सभी क्षेत्रों पर एक toString विधि ((खेतों पर @Getter/@Setter एनोटेशन का उपयोग विन्यस्त किया जा सकता @ToString एनोटेशन और
  • public getters और सभी क्षेत्रों के लिए निर्धारक के साथ विन्यस्त किया जा सकता है)।

@Builder एनोटेशन Builder कि Foo.builder() का उपयोग कर instantiated जा सकती है, कहा जाता है एक आंतरिक वर्ग उत्पन्न होगा।

सुनिश्चित करें कि आप equals, hashCode और toString तरीकों कॉन्फ़िगर के रूप में यदि आप एक दूसरे के लिए संदर्भ है लंबोक के साथ दो वर्गों है तो आप डिफ़ॉल्ट मामले में एक अनंत लूप के साथ अंत के रूप में दोनों वर्गों में अन्य शामिल होंगे बनाने करो इन तरीकों से।

वहाँ भी है एक नया configuration system उदाहरण के लिए, आप का उपयोग करने की अनुमति देता है कि, धाराप्रवाह setters ताकि आप के और अधिक कम बिल्डर को दूर कर सकते हैं कि आपके POJO परिवर्तनशील है:

new Foo().setId(3).setTitle("title)... 

एक और दृष्टिकोण के लिए आप कर सकते हैं Aspect-oriented programming (एओपी) और AspectJ पर देखें। एओपी आपको अपने वर्गों को "पहलुओं" में काटने की अनुमति देता है और फिर प्री-कंपाइलर का उपयोग करके कुछ नियमों का उपयोग करके उन्हें एक साथ चिपकाता है। उदाहरण के लिए आप कस्टम एनोटेशन और एक पहलू का उपयोग करके, लॉमोकॉक वास्तव में क्या कार्यान्वित कर सकते हैं। हालांकि यह एक काफी उन्नत विषय है, और शायद अधिक हो सकता है।

+0

मुझे एहसास हुआ कि 'जीसन' वास्तव में 'ऑब्जेक्ट' को deserialize करने के लिए एक बहुत ही समान दृष्टिकोण का उपयोग करता है, जिसमें यह प्रत्येक 'फ़ील्ड' को प्रारंभ करने के लिए प्रतिबिंब का उपयोग करता है। एक ही प्रतिबिंब कार्यान्वयन के आधार पर एक निर्माता ऐसा बुरा विचार नहीं हो सकता है। तुम क्या सोचते हो? – buildpattern

+1

@buildpattern यह एक भयानक विचार है जैसा कि मैंने इंगित किया है। जीएसओएन ऐसा इसलिए करता है क्योंकि यह _has_ करने के लिए है। आप संकलित समय प्रकार सुरक्षा खो देते हैं, जिसका अर्थ है कि आप किसी भी समय रनटाइम त्रुटियों को मार सकते हैं, और आप गति खो देते हैं। जब तक आप बॉयलरप्लेट को कम करने के लिए ** ** ** ** ** और ** ** ** प्रतिबिंब का उपयोग न करें। –

4

शायद Project Lombok (हाँ वेबसाइट बदसूरत है) आप के लिए एक विकल्प है। लॉमोकोक एनोटेशन के आधार पर आपकी कक्षाओं में कोड इंजेक्ट करता है।

लंबोक के साथ आप उत्पन्न ही टिककर खेल, setters, toString(), hashCode() और equals() को @Data एनोटेशन का उपयोग:

@Data 
public class Foo { 
    public int id; 
    public String title; 
    public boolean change; 
} 

@Data documentation section पर उदाहरण पर एक नज़र डालें उत्पन्न कोड को देखने के लिए।

लंबोक @Builder भी प्रदान करता है जो आपकी कक्षा के लिए एक निर्माता बनाता है।

@Builder 
public class Foo { 
    public int id; 
    public String title; 
    public boolean change; 
} 

अब आप कर सकते हैं::

Foo foo = Foo.builder() 
    .id(123) 
    .title("some title") 
    .change(true) 
    .build(); 
0

मैंने POJO की धाराप्रवाह प्रारंभ करने के लिए एक छोटी लाइब्रेरी CakeMold बनाई। यह प्रतिबिंब का उपयोग करता है, निश्चित रूप से तेज़ नहीं है। लेकिन परीक्षण लिखने की आवश्यकता होने पर बहुत उपयोगी हो सकता है।

Person person = CakeMold.of(Person.class) 
    .set("firstName", "Bob") 
    .set("lastName", "SquarePants") 
    .set("email", "[email protected]") 
    .set("age", 22) 
    .cook(); 
1

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

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