2010-07-08 18 views
17

मैं नीचे start() कैसे कॉल करूं?जावा जेनरिक + बिल्डर पैटर्न

package com.example.test; 

class Bar {} 

public class Foo<K> 
{ 
    final private int count; 
    final private K key; 

    Foo(Builder<K> b) 
    { 
     this.count = b.count; 
     this.key = b.key; 
    } 

    public static class Builder<K2> 
    { 
     int count; 
     K2 key; 

     private Builder() {} 
     static public <K3> Builder<K3> start() { return new Builder<K3>(); } 
     public Builder<K2> setCount(int count) { this.count = count; return this; } 
     public Builder<K2> setKey(K2 key) { this.key = key; return this; } 
     public Foo<K2> build() { return new Foo(this); } 
    } 

    public static void main(String[] args) 
    { 
     Bar bar = new Bar(); 
     Foo<Bar> foo1 = Foo.Builder.start().setCount(1).setKey(bar).build(); 
     // Type mismatch: cannot convert from Foo<Object> to Foo<Bar> 

     Foo<Bar> foo2 = Foo.Builder<Bar>.start().setCount(1).setKey(bar).build(); 
     // Multiple markers at this line 
     // - Bar cannot be resolved 
     // - Foo.Builder cannot be resolved 
     // - Syntax error on token ".", delete this token 
     // - The method start() is undefined for the type Foo<K> 
     // - Duplicate local variable fooType mismatch: cannot convert from Foo<Object> to Foo<Bar> 

     Foo<Bar> foo3 = Foo<Bar>.Builder.start().setCount(1).setKey(bar).build(); 
     // Multiple markers at this line 
     // - Foo cannot be resolved 
     // - Syntax error on token ".", delete this token 
     // - Bar cannot be resolved  
    } 
} 

उत्तर

23

आप करीब थे:

Foo.Builder.<Bar> start().setCount(1).setKey(bar).build(); 

चीयर्स! :)

पीएस यदि संकलक विधि के प्रकार पैरामीटर का अनुमान नहीं लगा सकता है, तो आप इसे obj.<Type> method(...) पर कॉल करके मजबूर कर सकते हैं।

P.P.S आप उपयोग करना चाहते हो सकता है:

public Foo<K2> build() { 
    return new Foo<K2>(this); 
} 

बचें कच्चे प्रकार का उपयोग कर।

+1

हर बार जब आप किसी विधि में एक स्पष्ट प्रकार का तर्क लिखते हैं, तो भगवान बिल्ली का बच्चा मारता है;) – sfussenegger

+0

आह, इसलिए आप जेनेरिक प्रकारों के साथ स्थिर विधियों को निर्दिष्ट करते हैं। धन्यवाद! –

+0

@sfussenegger: ठीक है, तो ऐसा करने का दूसरा तरीका है? –

13

एंड्री की विधि ठीक है, लेकिन अधिकांश प्रोग्रामर शायद अज्ञात वाक्यविन्यास के साथ संघर्ष करेंगे। इस तरह उपयोग करना आसान हो सकता है:

static public <K3> Builder<K3> start(Class<K3> cls) { return new Builder<K3>(); } 

Foo<Bar> foo1 = Foo.Builder.start(Bar.class).setCount(1).setKey(bar).build(); 

कक्षा केवल सामान्य प्रकार के साथ मदद करने के लिए पास की जाती है। यह सुंदर नहीं है, लेकिन कम से कम वाक्यविन्यास सामान्य ज्ञान है।

Foo<Bar> foo1 = Foo.Builder.startWithKey(bar).setCount(1).build(); 
-2

यह जावा 8.

public class Builder<T> { 
    private T instance; 
    private boolean ifCond = true; // default 
    public Builder(Class<T> clazz){ 
     try { 
      instance = clazz.newInstance(); 
     } catch (InstantiationException | IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
    } 

    public Builder<T> with(Consumer<T> setter){ 
     if(ifCond) 
      setter.accept(instance); 
     return this; 
    } 

    public T get(){ 
     return instance; 
    } 

    public static <T> Builder<T> build(Class<T> clazz) { 
     return new Builder<>(clazz); 
    } 

    public Builder<T> If(BooleanSupplier condition){ 
     this.ifCond = condition.getAsBoolean(); 
     return this; 
    } 

    public Builder<T> endIf(){ 
     this.ifCond = true; 
     return this; 
    } 
} 

How to use it: 

List list = Arrays.asList(1, 2, 3, 4, 5) 

System.out.println(
    Builder.build(Sample.class) 
      .with(s -> s.setId(1)) 
      .with(s -> s.setName("Sample object")) 
      .with(s -> s.setList(list)) 
      .get() 
); 

// Java Properties 
System.out.println(
    Builder.build(Properties.class) 
      .with(p -> p.put("one", 1)) 
      .with(p -> p.put("two", 2)) 
      ... 
      .get() 

); 
System.out.println(Builder.build(Properties.class) 
        .with(p -> p.put("one", 1)) 
        .If(() -> false) // any expression return boolean 
        .with(p -> p.put("two", 2)) 
        .with(p -> p.put("three", 3)) 
        .endIf() 
        .with(p -> p.put("four", 4)) 
        .get() 

); // output=> {one=1, four=4} 

https://howtocodetutorial.wordpress.com/generic-builder-pattern-in-java-8/

में जेनेरिक बिल्डर पैटर्न के अपने कार्यान्वयन है:

एक अन्य विकल्प सही सामान्य प्रकार का ऑब्जेक्ट के साथ भाग शुरू करने के लिए किया जाएगा

+0

मैं आपको एक कम वोट नहीं दूंगा, सिर्फ स्पष्टीकरण क्यों यह अच्छा उदाहरण नहीं है और न ही अभ्यास। बिल्डर पैटर्न रखने का पूरा उद्देश्य बड़े कन्स्ट्रक्टर से बचने के लिए है, और यह केवल ** अपरिवर्तनीय ** ऑब्जेक्ट्स के साथ होता है। यदि आपके पास म्यूटेबल ऑब्जेक्ट है, तो आप केवल इंस्टेंस बना सकते हैं और सेटर्स को कॉल कर सकते हैं। लेकिन अपरिवर्तनीय के साथ, आपको कन्स्ट्रक्टर में सभी मूल्यों को पारित करने की आवश्यकता है, इसमें एक समस्या या कन्स्ट्रक्टर संयोजनों की घातीय वृद्धि है, इसलिए निर्माता पैटर्न। तो, ऑब्जेक्ट बिल्डर बनाता है अपरिवर्तनीय होना चाहिए। आपके उदाहरण में, आप सेटर्स का उपयोग कर रहे हैं और बिल्डर पैटर्न के पूरे उद्देश्य के साथ खो गया है। – Vajda

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