2010-09-08 16 views
5

मैं जावा में एक वर्ग पदानुक्रम है मान लीजिए:डिज़ाइन पैटर्न पैटर्न?

interface Item { ... }; 
class MusicBox implements Item { ... }; 
class TypeWriter implements Item { ... }; 
class SoccerBall implements Item { ... }; 

और मैं एक ही पैकेज में एक और वर्ग है:

class SpecialItemProcessor { 
    public void add(Item item) 
    { 
     /* X */ 
    } 
} 

जहां मैं कुछ प्रत्येक आइटम प्रकार के लिए अलग करना चाहते हैं, लेकिन मैं डॉन अलग-अलग Item कक्षाओं (MusicBox, TypeWriter, SoccerBall) में उस क्रिया को परिभाषित नहीं करना चाहते हैं।

एक तरीका यह संभाल करने के लिए है:

class SpecialItemProcessor { 
    public void add(Item item) 
    { 
     if (item instanceof MusicBox) 
     { 
      MusicBox musicbox = (MusicBox)item; 
      ... do something ... 
     } 
     else if (item instanceof MusicBox) 
     { 
      TypeWriter typewriter = (TypeWriter)item; 
      ... do something ... 
     } 
     else if (item instanceof SoccerBall) 
     { 
      SoccerBall soccerball = (SoccerBall)item; 
      ... do something ... 
     } 
     else 
     { 
      ... do something by default ... 
     } 
    } 
} 

यह काम करता है लेकिन यह वास्तव में भद्दा लगता है। क्या मुझे ऐसा करने का बेहतर तरीका है, जब मुझे विशेष मामलों के बारे में पता है? (जाहिर है, अगर Item एक विधि शामिल doSomethingSpecial तो मैं सिर्फ इतना है कि आइटम की विधि यह क्या टाइप कर रहा है देखभाल के बिना कॉल कर सकते हैं, लेकिन स्वयं आइटम मैं इसे से कैसे निपटते हैं के भीतर होने के लिए है कि भेदभाव चलेगा कि मैं नहीं चाहता?)

+0

मुझे कोई जवाब नहीं है, लेकिन एक्शनस्क्रिप्ट 3 में जाहिर है कि आप एक स्ट्रिंग से कक्षा को तुरंत चालू कर सकते हैं (यानी 'com.djw.MusicBox' एक संगीत बॉक्स को चालू कर सकता है), है जावा में शायद इस तरह की चीज संभव है? केवल एक सलाह! – danjah

+0

@ डैन: 'कक्षा # नामनाम()'। हालांकि मैं यहां मूल्य पर सवाल करता हूं। – BalusC

उत्तर

2

मुझे लगता है कि मैं नियंत्रण से उलट करने के विचार का उपयोग करने के लिए जा रहा हूँ और visitor pattern:

interface Item { 
    public void accept(Visitor visitor); 
    ... 

    public interface Visitor { 
     public void visit(Item item); 
    } 
} 


class MusicBox implements Item { 
    public interface Visitor extends Item.Visitor { 
     public void visitMusicBox(MusicBox item); 
    } 
    ... 
    @Override public accept(Item.Visitor visitor) 
    { 
     if (visitor instanceof MusicBox.Visitor) 
     { 
      ((MusicBox.Visitor)visitor).visitMusicBox(this); 
     } 
    } 
} 

class TypeWriter implements Item { 
    public interface Visitor extends Item.Visitor { 
     public void visitTypeWriter(TypeWriter item); 
    } 
    ... 
    @Override public accept(Item.Visitor visitor) 
    { 
     if (visitor instanceof TypeWriter.Visitor) 
     { 
      ((TypeWriter.Visitor)visitor).visitTypeWriter(this); 
     } 
    } 
} 

class SoccerBall implements Item { 
    public interface Visitor extends Item.Visitorr { 
     public void visitSoccerBall(SoccerBall item); 
    } 
    ... 
    @Override public accept(Item.Visitor visitor) 
    { 
     if (visitor instanceof SoccerBall.Visitor) 
     { 
      ((SoccerBall.Visitor)visitor).visitSoccerBall(this); 
     } 
    } 
} 

और फिर निम्न है, जो कम से कम प्रति add() कॉल instanceof एक करने के लिए चेक कम कर देता है कर :

class SpecialItemProcessor 
    implements 
     MusicBox.Visitor, 
     TypeWriter.Visitor, 
     SoccerBall.Visitor, 
     Item.Visitor 
{ 
    public void add(Item item) 
    { 
     item.accept(this); 
    } 
    @Override public void visitMusicBox(MusicBox item) 
    { 
     ... 
    } 
    @Override public void visitTypeWriter(TypeWriter item) 
    { 
     ... 
    } 
    @Override public void visitSoccerBall(SoccerBall item) 
    { 
     ... 
    } 
    @Override public void visit(Item item) 
    { 
     /* not sure what if anything I should do here */ 
    } 
} 
0

आप आइटम के लिए पुल पैटर्न बना सकते हैं, जिसमें दूसरी तरफ जोड़ने के लिए संबंधित प्रक्रियाएं होती हैं() कहा जाता है। आप मिश्रण में एक कारखाना विधि भी जोड़ सकते हैं।

class SpecialItemProcessor { 
    public void add(Item item) 
    { 
    Process p = Item.createCorrespondingProcessor(p); 
    p.doWhenAddin(); 
    } 
} 

उम्मीद है कि इससे मदद मिलती है।

+0

वह वाक्यविन्यास क्या है? और, शुरुआत में इसे निर्दिष्ट करने से पहले आप 'p' का उपयोग कैसे करते हैं? – jjnguy

+0

यह PHP नहीं है ... सही संस्करण: 'p.doWhenAddin()' – TheLQ

+0

क्षमा करें, आखिरकार मैंने कुछ सी ++ वाक्यविन्यास में फेंक दिया। यह स्रोत कोड जावा है। संबंधित संसाधित प्रोसेसर विधि एक फैक्ट्री विधि है जो आइटम के वर्ग पदानुक्रम से जुड़ी प्रोसेसर के वर्ग पदानुक्रम से संबंधित उपयुक्त वर्ग बनाती है। – Baltasarq

7

जावा में आप एक आगंतुक (जैसे) पैटर्न के साथ एकाधिक प्रेषण कर सकते हैं। आइटम कार्यान्वयन में प्रसंस्करण तर्क को शामिल करने की आवश्यकता नहीं है, उन्हें केवल accept() विधि की आवश्यकता है।

public interface Item { 
/** stuff **/ 

void processMe(ItemProcessor processor); 

} 

public interface ItemProcessor { 

void process(MusicBox box); 

void process(SoccerBall ball); 

//etc 

} 

public class MusicBox implements Item { 

    @Override 
    public void processMe(ItemProcessor processor) { 
    processor.process(this); 
    } 

} 

public class ItemAddingProcessor implements ItemProcessor { 

    public void add(Item item) { 
    item.processMe(this); 
    } 

    @Override 
    public void process(MusicBox box) { 
    //code for handling MusicBoxes 
    //what would have been inside if (item instanceof MusicBox) {} 
    } 

//etc 
} 
+0

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

+0

यह संकलित होगा, आप पार-निर्भरता के बीच हो सकते हैं जावा में कक्षाएं हालांकि, आपके पास .jars के बीच कॉर्स-निर्भरता नहीं हो सकती है, इसलिए यदि आइटम और आइटमप्रोसेसर अलग-अलग हैं तो यह काम नहीं करेगा। – amorfis

+0

@ जेसन: हाँ, यह संकलित करता है :) यह सिर्फ चीजों को फ़्लिप करने का एक तरीका है ताकि एक विधि होने की बजाय यह पता लगाने की कोशिश की जा सके कि किस प्रकार के आइटम को संभालना है, आपके पास विभिन्न प्रकार के आइटम स्वयं को पास करते हैं एक तरीका है कि उनके हैंडलिंग है। संकलन समय युग्मन उसमें उल्टा हो सकता है, अगर आपके पास ऐसा था, तो एप्लिकेशन के आस-पास के कई स्थानों पर ब्लॉक के उदाहरण के साथ, जब आप एक नया आइटम प्रकार बनाते हैं, तो जब आप सभी इंटरफ़ेस को कार्यान्वित करते हैं, तो उसे अद्यतन करना बहुत आसान होता है वह बदल गया – Affe

0

आइटम इंटरफ़ेस में कुछ कॉलबैक फ़ंक्शन को परिभाषित क्यों नहीं करें?

public Interface Item { 
    void onCallBack(); 
} 

फिर प्रत्येक श्रेणी में जो संगीत बॉक्स जैसे आइटम लागू करता है, उसे कॉलबैक फ़ंक्शन को कार्यान्वित करना चाहिए।

public class MusicBox { 
    @override 
    public void onCallBack() { 
    // business logic 
    ... 
    ... 
    } 
} 

फिर आप एक प्रेषक बना सकते हैं, जिसका नाम आप "स्पेशलइटम प्रोसेसर" है।

public SpecialItemProcessor { 
    private final Item _item; 

    public SpecialItemProcessor(Item item) { 
    _item = item; 
    } 

    public dispatch() { 
    _item.onCallBack() 
    } 
} 

और फिर, ग्राहक वर्ग जो SpecialItemProcessor बस, विधि कह सकते हैं की तरह होता है में:

public void XXXX() { 
    .... 
    SpecialItemProcessor specialItemProcessor = new SpecialItemProcessor(new MusicBox()); 
    specialItemProcessor.dispatch(); 
    .... 
} 

वास्तव में, सी ++ में, इस गतिशील बाध्यकारी है। और यही कारण है कि शुद्ध अमूर्त वर्ग मौजूद है ...

+1

प्रश्न पढ़ें: "जहां मैं प्रत्येक आइटम प्रकार के लिए कुछ अलग करना चाहता हूं, ** लेकिन मैं अलग-अलग आइटम वर्ग ** (संगीत बॉक्स, टाइपवाइटर, सॉकरबॉल) में उस क्रिया को परिभाषित नहीं करना चाहता हूं। " –

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