2008-10-18 17 views
5

मेरे पास एक कक्षा है जिस पर मैं कई (~ 20 +) कॉन्फ़िगरेशन विकल्पों को अनुमति देना चाहता हूं। प्रत्येक विकल्प कार्यक्षमता के एक टुकड़े को चालू या बंद करता है, या अन्यथा संचालन बदलता है। इसे सुविधाजनक बनाने के लिए, मैंने डिफ़ॉल्ट मानों के साथ एक अलग विकल्प वर्ग को कोड किया। हालांकि, मुझे यह निर्धारित करने के लिए कि कैसे तरीकों का व्यवहार करना चाहिए, मुझे गार्ड कोड की स्थिति के साथ अपना कोड कूड़ा था। मैं लगभग पूरा कर चुका हूं, लेकिन अब कोड गंध लग रहा है।क्या कक्षा में "विकल्प" जोड़ने के लिए कोई पैटर्न है?

क्या इस तरह की कक्षा को लागू करने के लिए कोई पसंदीदा तरीका/पैटर्न है?

संपादित करें: अधिक विशेष रूप से, मैं एक पार्सिंग कक्षा पर काम कर रहा हूं। प्रत्येक विकल्प मूल पार्सिंग एल्गोरिदम के परस्पर अनन्य हिस्सों को कॉन्फ़िगर करता है। उदाहरण के लिए मुझे लगता है कि नीचे की तरह लग रही मेरी कक्षा में कई क्षेत्रों है:

if (this.Option.UseIdAttribute) 
     attributeIDs = new Hashtable(); 
else 
     attributeIDs = null; 


    public Element GetElementById(string id) 
    { 
     if (string.IsNullOrEmpty (id)) 
      throw new ArgumentNullException("id"); 

     if (attributeIDs == null) 
      throw new Exception(ExceptionUseIdAttributeFalse); 

     return attributeIDs[id.ToLower()] as Element; 
    } 
+0

जब तक आप कोड पोस्ट यह बहुत कहना मुश्किल है ... – johnstok

उत्तर

5

कैसे Decorator pattern के बारे में? यह गतिशील रूप से कक्षा में व्यवहार जोड़ने के लिए डिज़ाइन किया गया है।

+0

मैं इस बारे में सोचा है, लेकिन मैं अगर यह फिट होगा देखने के लिए फिर से कोड की समीक्षा करेंगे। शुरू में मैंने सोचा कि यह थोड़ा अधिक होगा, और मैं कक्षा bloat से बचना चाहता था। – Nescio

+0

सजावटी पैटर्न भी मेरा जवाब होगा। आपको इसका उपयोग उसी तरीके से करने की ज़रूरत नहीं है जिसमें इसे गोफ बुक या हेडफ़र्स्ट डिज़ाइन पैटर्न में प्रस्तुत किया गया है - पैटर्न व्यंजन नहीं हैं। अपनी जरूरतों को पूरा करने के लिए इसे आकार दें। – Sandman

0

मैं Command पैटर्न के बारे में सोच रहा हूं।

यह कुछ ऐसा दिखाई देगा:

public class MyClass { 

    interface Command { 
    void execute(int a); 
    } 

    static class DoThisSimpleCommand implements Command { 
    void execute(int a) { 
     // do this simple 
    } 
    } 

    static class DoThisAnotherWayCommand implements Command { 
    void execute(int a) { 
     // do this another way 
    } 
    } 

    private Command doThisCommand; 

    MyClass() { 
    initDoThisCommand(); 
    } 

    private void initDoThisCommand() { 
    if (config.getDoThisMethod().equals("simple")) { 
     doThisCommand = new DoThisSimpleCommand(); 
    } else { 
     doThisCommand = new DoThisAnotherWayCommand(); 
    } 
    } 

    void doThis(int a) { 
    doThisCommand.execute(a); 
    } 
} 

दूसरे शब्दों में, आप एक कार्यान्वयन की ज़िम्मेदारी नियुक्त करते हैं जिसे आप निर्माण पर तत्काल करते हैं। अब आपका ऐसा यह सिर्फ प्रतिनिधियों और वास्तविक कार्यक्षमता को अपनी कक्षा में साफ कर दिया गया है।

1

वास्तव में इस उद्देश्य के लिए बिल्डर पैटर्न नामक एक और पैटर्न है। आमतौर पर उपयोगी होता है जब आपके पास कक्षा होती है लेकिन प्रत्येक 'कॉन्फ़िगरेशन' विकल्प को केवल कुछ संयोजनों में वैकल्पिक बनाया जा सकता है। (http://en.wikipedia.org/wiki/Builder_pattern, लेकिन यह वास्तव में मेरे परिदृश्य का वर्णन नहीं करता है)।

आप दो कक्षाएं बनाते हैं - जिस वर्ग को आप बनाना चाहते हैं, और निर्माता। बिल्डर क्लास वह वर्ग है जो विकल्पों का संयोजन वैकल्पिक विकल्प है, जो संयोजन समझ में आता है, आदि।

उदाहरण के लिए, आप सलाद का प्रतिनिधित्व करना चाहते हैं - लेकिन केवल कुछ अवयवों का स्वाद अच्छा है, इसलिए केवल उनको बनाया जाना चाहिए।

Class Salad { 
    private Veggie v; 
    private Egg e; 
    private Meat m; 
    // etc etc, lots of properties 
    //constructor like this is nice 
    Salad(SaladBuilder builder) { 
     //query the builder to actually build the salad object. 
     //getVeggie() will either return the supplied value, 
     //or a default if none exists. 
     this.v = builder.getVeggie(); 
     //rest of code omitted 
    } 

    //otherwise this constructor is fine, but needs a builder.build() method 
    Salad(Veggie v, Meat m, Egg e) { //code omitted 
    } 
} 

class SaladBuilder { 
    //some default, or left to null depending on what is needed 
    private Veggie v = SOME_DEFAULT_VEGGIE; 
    private Egg e; 
    private Meat m; 
    // etc etc, lots of properties. 

    //similar functions for each ingredient, 
    //or combination of ingredients that only make sense together 
    public SaladBuilder addIngredient(Meat m) { 
     this.m = m; 
     return this; 
    } 

    public SaladBuilder addIngredient(Veggie v) { 
     this.v = v; 
     return this; 
    } 

    public Salad build(){ 
     // essentially, creates the salad object, but make sure optionals 
     // are taken care of here. 
     return new Salad(getBeggie(), getMeat(), getEgg()); 
    } 
} 

के उपयोग का उदाहरण

Salad s = new SaladBuilder().addIngredient(v).addIngredient(m).build(); 
2

विकल्प/बंद कार्यक्षमता पर बारी के लिए, मुझे लगता है कि डेकोरेटर के रूप में @Thomas ओवेन्स का कहना है जाने के लिए रास्ता है। मैं उन विकल्पों के बारे में थोड़ा अधिक चिंतित हूं जो कार्यों को बदलते हैं। अगर इन परिचालनों को जंजीर नहीं बनाया जा सकता है तो सजावटी कई काम नहीं करते हैं। उदाहरण के लिए, अपने कोड नज़र डालती है कि जैसे:

public void ActionABC() 
{ 
    if (options.DoA) 
    { 
     A(); 
    } 

    if (options.DoB) 
    { 
     B(); 
    } 

    if (options.DoC) 
    { 
     C(); 
    } 
} 

public void ActionCAB() 
{ 
    if (options.DoC) 
    { 
     C(); 
    } 

    if (options.DoA) 
    { 
     A(); 
    } 

    if (options.DoB) 
    { 
     B(); 
    } 
} 

यह डेकोरेटर के साथ संभाल करने के लिए के रूप में रचना के क्रम प्रत्येक कार्रवाई विधि के लिए के लिए अलग है मुश्किल होगा।

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

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

+0

20+ बूलियन विकल्प दस लाख से अधिक संयोजन हैं, है ना? – erickson

0

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

1

इस तरह कुछ के बारे में क्या?

IdMap elementsById = (options.useIdAttribute) ? new IdMapImpl() : new NullIdMap(); 

public Element getElementById(final string id) { 
    return elementsById.get(id); 
} 

निम्नलिखित प्रकार के आधार पर:

interface IdMap { 
    Element get(String id); 
} 

class NullIdMap implements IdMap { 
    public Element get(final String id) { 
     throw new Exception(/* Error message */); 
    } 
} 

class IdMapImpl implements IdMap { 
    Map<String, Element> elements = new HashMap<String, Element>(); 

    public Element get(final String id) { 
     rejectEmpty(id); 
     return elements.get(id.toLowerCase()); 
    } 
} 

यहाँ हम विशेष मामले को संभालने के लिए NullObject पैटर्न के उपयोग जहां useIdAttribute अक्षम किया गया है बनाते हैं। निस्संदेह एक व्यापार-बंद है - पार्सर क्लास स्वयं अधिक अभिव्यक्तिपूर्ण है, जबकि अब 1 से 4 प्रकार हैं। यह रिफैक्टरिंग केवल विधि प्राप्त करने के लिए ओवरकिल की तरह प्रतीत हो सकती है, लेकिन जब आप 'put()' विधि जोड़ते हैं इत्यादि। यह एक वर्ग (NullIdMap) में 'विशेष मामला' तर्क को स्थानीयकरण का लाभ है।

एक रणनीति या नीति पैटर्न की तरह कुछ का उपयोग करते हुए यहाँ उपयोगी हो सकता है [rejectEmpty एक सहायक विधि है कि एक अपवाद फेंकता है तो कोई रिक्त स्ट्रिंग पारित कर दिया है।]

+0

यह उदाहरण जावा में सी # की बजाय जावा में है, लेकिन यह अभी भी निर्देशक है। – johnstok

0

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

आपके परिदृश्य में, यदि आपके पार्सिंग क्लास में आम तौर पर समान प्रकार के व्यवहार (कुछ में, कुछ बाहर) होता है लेकिन आंतरिक एल्गोरिदम बदलते हैं, तो ऐसा कुछ है जिसे आप कार्यान्वित करना चाहते हैं।

http://en.wikipedia.org/wiki/Strategy_pattern

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