2012-05-12 13 views
5

मैं विज़िटर पैटर्न के साथ थोड़ा सा असभ्य हूं, लेकिन मेरे पास एक ऐसा कार्य है जिसके लिए विज़िटर कार्यान्वयन होना आवश्यक है (यदि मैं "उदाहरण" चेक से बचना चाहता हूं)।"exampleof" को प्रतिस्थापित करने के लिए विज़िटर पैटर्न का उपयोग कैसे करें

मेरे पास एक वर्ग है जो कई gwt तत्वों के लिए एक रैपर है: लेबल, पैनल, विजेट (चेकबॉक्स, सूची बॉक्स, टेक्स्टबॉक्स आदि हो सकता है)। मैं UI के समान भागों के संग्रह के रूप में एक सरणी का उपयोग करता हूं। जैसे लेबल + चेकबॉक्स, लेबल + टेक्स्ट बॉक्स; लेबल + बटन इत्यादि

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

public class MyWidgets { 
    private String stringLabel; 
    private Widget widget; 
    private Panel panel; 

    public MyWidgets(String stringLabel, Widget widget) { 
     this.stringLabel = stringLabel; 
     this.widget = widget; 

     initPanel(stringLabel, widget); 
    } 

    public MyWidgets(ConstructedClass cs, Widget widget) { 
     this.widget = widget; 

     initPanel(cs, widget); 
    } 

    private initPanel(String label, Widget widget) { 
     panel = SomeStaticUtilityClass.initPanel(new Label(label), widget); 
    } 

    private initPanel(ConstructedClass cs, Widget widget) { 
     panel = SomeStaticUtilityClass(cs, widget); 
    } 
} 

कुछ इस तरह (मैं इसे अधिकतम सार करने की कोशिश की, वास्तव में यह और अधिक कठिन है):

यहाँ मैं क्या है का एक उदाहरण है।

तो मैं एक समाधान "instanceof" का उपयोग किया है:

private initPanel(Object object, Widget widget) { 
    if(object instanceof String) { 
    panel = SomeStaticUtilityClass.initPanel(new Label(label), widget); 
    } 
    if(object instanceof ConstructedClass) { 
    panel = SomeStaticUtilityClass.initPanelFromObject(cs, widget); 
    } 
} 

मैं "instanceof" से बचा लिया और उसके अतिभारित संस्करण के बिना सिर्फ एक निर्माता और यहां तक ​​कि, अगर यह संभव है, एक init विधि छोड़ करना चाहते हैं । आपके सुझावों, सहायता के लिए अग्रिम धन्यवाद।

पी.एस> मैं फिर कहता हूँ, उस वर्ग के ऊपर निर्मित है, और कुछ गलतफहमी की तरह दिखता है, विशेष रूप से इस स्ट्रिंग लेबल :)

+0

हम्म .. कुछ पंक्ति के साथ अजीब लगता है: "पैनल = कुछ स्टेटिक यूटिलिटी क्लास (सीएस, विजेट);"। क्या StStaticUtility क्लास या एक विधि क्लास है? :) – Javaguru

+0

मैंने उदाहरण – Dragon

उत्तर

3

IMO, अपने मौजूदा समाधान के साथ, दो कंस्ट्रक्टर्स के साथ, ठीक है।

आप रणनीति पैटर्न का उपयोग कर सकते हैं और अपने कन्स्ट्रक्टर को ऑब्जेक्ट के बजाय PanelProvider इंटरफ़ेस का उदाहरण ले सकते हैं। इस इंटरफ़ेस में निम्न विधि होगी:

Panel createPanel(Widget widget); 

। ग्राहक StringPanelProvider का उदाहरण या ConstructedClassPanelProvider का उदाहरण कन्स्ट्रक्टर को पास करेंगे। StringPanelProvider कार्यान्वयन

public MyWidgets(PanelProvider panelProvider, Widget widget) { 
    this.widget = widget; 
    this.panel = panelProvider.createPanel(widget); 
} 

और तरह

public class StringPanelProvider implements PanelProvider { 

    private String s; 

    public StringPanelProvider(String s) { 
     this.s = s; 
    } 

    @Override 
    public Panel createPanel(Widget widget) { 
     return SomeStaticUtilityClass.initPanel(new Label(s), widget); 
    } 
} 

ConstructedClassPanelProvider ही लगेगा दिखेगा: आपका निर्माता इस प्रकार की तरह लग रहे हैं।

तुम सच में आगंतुक पैटर्न का उपयोग करने के लिए तो आप एक छोटा सा ऊपर को संशोधित करना होगा चाहते हैं:

public interface Visitable { 
    void accept(Visitor visitor); 
} 

public interface Visitor { 
    void stringVisited(String s); 
    void constructedClassVisited(ConstructedClass cs); 
} 

public class StringVisitable { 
    private String s; 

    public StringVisitable(String s) { 
     this.s = s; 
    } 

    void accept(Visitor visitor) { 
     visitor.stringVisited(s); 
    } 
} 

// similar for ConstructedClassVisitable 

public MyWidgets(Visitable visitable, final Widget widget) { 
    this.widget = widget; 
    visitable.accept(new Visitor() { 
     public void stringVisited(String s) { 
      panel = SomeStaticUtilityClass.initPanel(new Label(label), widget); 
     } 

     public void constructedClassVisited(ConstructedClass cs) { 
      panel = SomeStaticUtilityClass.initPanelFromObject(cs, widget); 
     } 
    }); 
} 

लेकिन यह मेरे लिए overengineering तरह दिखता है।

public interface ConstructionArgVisitor { 
    void visit(LabelText text); 

    void visit(ConstructedClass clazz); 
} 

public interface ConstructionArg { 
    void accept(ConstructionArgVisitor visitor); 
} 

public class LabelText implements ConstructionArg { 
    private final String text; 

    public LabelText(String str) { 
     this.text = str; 
    } 

    @Override 
    public void accept(ConstructionArgVisitor visitor) { 
     visitor.visit(this); 
    } 

    public String getString() { 
     return this.text; 
    } 
} 

public class ConstructedClass implements ConstructionArg { 
    @Override 
    public void accept(ConstructionArgVisitor visitor) { 
     visitor.visit(this); 
    } 
} 

public class MyWidgets implements ConstructionArgVisitor { 
    private String stringLabel; 
    private Widget widget; 
    private Panel panel; 

    public MyWidgets(ConstructionArg constructionArg, Widget widget) { 
     this.widget = widget; 
     constructionArg.accept(this); 
    } 

    @Override 
    public void visit(LabelText labelText) { 
     this.stringLabel = labelText.getString(); 
     this.panel = SomeStaticUtilityClass.initPanel(new Label(labelText.getString()), this.widget); 
    } 

    @Override 
    public void visit(ConstructedClass clazz) { 
     this.panel = SomeStaticUtilityClass.initPanelFromObject(clazz, this.widget); 
    } 
} 

यह समाधान बहुत जेबी Nizet जैसी ही है: visitor pattern का उपयोग कर

+0

को सही किया है, मुझे लगता है कि पैनल कारखाने के संयोजन के साथ रणनीति पैटर्न एक आगंतुक का उपयोग करने से अधिक उपयुक्त लगता है। – Javaguru

+0

दोनों प्रकार: आपका और क्रीमामा एक अच्छा है। वे मेरे लिए उपयोगी थे। बहुत बहुत धन्यवाद। – Dragon

2

एक कार्यान्वयन इस प्रकार है।इस कार्यान्वयन के ConstructorArgVisitor और जेबी निजेट के Visitor इंटरफेस के बीच का अंतर विधि नाम है। visit विधि ConstructorArgVisitor में अधिभारित है, जबकि जेबी निजेट के Visitor में, विधि नामों में उनमें प्रकार होता है (उदा।, stringVisited)। visit विधि को अधिभारित करना visitor pattern on the Wikipedia page के उदाहरण जैसा दिखता है।

मैं जेबी निजेट से सहमत हूं कि विज़िटर पैटर्न का उपयोग थोड़ा अधिक हो सकता है; हालांकि, यदि आप PanelProvider का उपयोग करते हैं क्योंकि जेबी निजेट अनुशंसा करता है, जब तक कि आपको पता न हो कि तर्क String या ConstructedClass समय से पहले है, तो आपको अभी भी instanceof चेक करने की आवश्यकता हो सकती है, जिसे आप टालने का प्रयास कर रहे हैं।

अब यह मेरी व्यक्तिगत वरीयता है, इसलिए यदि आप चाहें तो आप अवहेलना कर सकते हैं: कन्स्ट्रक्टर में काम न करने का प्रयास करें क्योंकि मिस्को हेवरी ने "Flaw: Constructor does Real Work" में सिफारिश की है। उदाहरण के लिए, आप निर्माण तर्क को कारखाने में स्थानांतरित कर सकते हैं।

public interface ConstructionArgVisitor<T> { 
    T visit(LabelText text); 

    T visit(ConstructedClass clazz); 
} 

public interface ConstructionArg { 
    <T> T accept(ConstructionArgVisitor<T> visitor); 
} 

public class LabelText implements ConstructionArg { 
    private final String text; 

    public LabelText(String str) { 
     this.text = str; 
    } 

    @Override 
    public <T> T accept(ConstructionArgVisitor<T> visitor) { 
     return visitor.visit(this); 
    } 

    public String getString() { 
     return this.text; 
    } 
} 

public class ConstructedClass implements ConstructionArg { 
    @Override 
    public <T> T accept(ConstructionArgVisitor<T> visitor) { 
     return visitor.visit(this); 
    } 
} 

public class MyWidgetsFactory implements ConstructionArgVisitor<MyWidgets> { 
    private final Widget widget; 

    public MyWidgetsFactory(Widget widget) { 
     this.widget = widget; 
    } 

    public MyWidgets createMyWidgets(ConstructionArg constructionArg) { 
     return constructionArg.accept(this); 
    } 

    @Override 
    public MyWidgets visit(LabelText text) { 
     return new MyWidgets(text.getString(), this.widget, SomeStaticUtilityClass.initPanel(
       new Label(text.getString()), this.widget)); 
    } 

    @Override 
    public MyWidgets visit(ConstructedClass clazz) { 
     return new MyWidgets(null, this.widget, SomeStaticUtilityClass.initPanelFromObject(clazz, this.widget)); 
    } 
} 

public class MyWidgets { 
    private final String stringLabel; 
    private final Widget widget; 
    private final Panel panel; 

    public MyWidgets(String stringLabel, Widget widget, Panel panel) { 
     this.stringLabel = stringLabel; 
     this.widget = widget; 
     this.panel = panel; 
    } 
} 

public static void main(String[] args) { 
    final Widget widget = ...; 
    final MyWidgetsFactory factory = new MyWidgetsFactory(widget); 

    // create MyWidgets from label text 
    final String str = ...; 
    final MyWidgets labelWidget = factory.createMyWidgets(new LabelText(str)); 

    // create MyWidgets from constructed class 
    final ConstructedClass clazz = ...; 
    final MyWidgets constructedClassWidget = factory.createMyWidgets(clazz); 
} 

मैं भी देखते हैं कि आप निर्माण के दौरान एक स्थिर विधि कॉल कर रहे हैं कि: निम्नलिखित ऊपर आगंतुक पैटर्न का एक संशोधित संस्करण का उपयोग करता है। हालांकि कई कोडबेस जीयूआई परीक्षण करने के लिए कुख्यात रूप से कठिन हैं, फिर भी आप "Flaw: Brittle Global State & Singletons" और "Guide: Writing Testable Code" पढ़ना चाहेंगे।

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