2010-11-24 12 views
8

मेरे पास ध्वज तर्क के साथ एक विधि है। मुझे लगता है कि एक विधि के लिए एक बूलियन गुजरना एक बुरा अभ्यास है (हस्ताक्षर जटिल करता है, "प्रत्येक विधि एक चीज करता है" सिद्धांत का उल्लंघन करता है)। मुझे लगता है कि विधि को दो अलग-अलग तरीकों से विभाजित करना बेहतर है। लेकिन अगर मैं ऐसा करता हूं, तो दो विधियां बहुत समान होंगी (कोड डुप्लिकेशन)।क्या ध्वज तर्क के साथ एक विधि को विभाजित करने के लिए कोई तकनीक है?

मुझे आश्चर्य है कि फ्लैग तर्क के साथ दो अलग-अलग तरीकों से विभाजित विधियों के लिए कुछ सामान्य तकनीकें हैं या नहीं।

यहाँ मेरी विधि (जावा) का कोड है:

int calculateNumOfLiveOrDeadNeighbors(Cell c, int gen, boolean countLiveOnes) { 
    int x = c.getX(); 
    int y = c.getY(); 
    CellState state; 
    int aliveCounter = 0; 
    int deadCounter = 0; 
    for (int i = x - 1; i <= x + 1; i++) { 
     for (int j = y - 1; j <= y + 1; j++) { 
     if (i == x && j == y) 
      continue; 
     state = getCell(i, j).getCellState(gen); 
     if (state == CellState.LIVE || state == CellState.SICK){ 
      aliveCounter++; 
     } 
     if(state == CellState.DEAD || state == CellState.DEAD4GOOD){ 
      deadCounter++; 
     } 
     } 
    } 
    if(countLiveOnes){ 
     return aliveCounter; 
    } 
    return deadCounter; 
} 

उत्तर

3

मैं इसे हर एक मामले पर निर्भर करता है लगता है ।

इस उदाहरण में आपके विचार में आपके पास दो विकल्प हैं।

आप दो में कॉल calculateNumOfLiveOrDeadNeighbors()

विभाजित करना चाहते हैं कहते हैं:

calculateNumOfLiveNeighbors() 

और

calculateNumOfDeadNeighbors() 

आप किसी अन्य विधि के लिए लूप को स्थानांतरित करने के Template Method उपयोग कर सकते हैं। आप दो तरीकों से मृत/जीवित कोशिकाओं को गिनने के लिए इसका उपयोग कर सकते हैं।

private int countCells(Cell c, int gen, Filter filter) 
{ 
    int x = c.getX(); 
    int y = c.getY(); 
    CellState state; 
    int counter = 0; 
    for (int i = x - 1; i <= x + 1; i++) 
    { 
     for (int j = y - 1; j <= y + 1; j++) 
     { 
      if (i == x && j == y) 
       continue; 
      state = getCell(i, j).getCellState(gen); 
      if (filter.countMeIn(state)) 
      { 
       counter++; 
      } 
     } 
    } 
    return counter; 
} 

private interface Filter 
{ 
     boolean countMeIn(State state); 
} 

public int calculateNumOfDeadNeighbors(Cell c, int gen) 
{ 
    return countCells(c, gen, new Filter() 
         { 
          public boolean countMeIn(CellState state) 
          { 
           return (state == CellState.DEAD || state == CellState.DEAD4GOOD); 
          } 
         }); 
    } 

public int calculateNumOfLiveNeighbors(Cell c, int gen) 
{ 
    return countCells(c, gen, new Filter() 
         { 
          public boolean countMeIn(CellState state) 
          { 
           return (state == CellState.LIVE || state == CellState.SICK); 
          } 
         }); 
    } 

यह बोझिल है, शायद दर्द के लायक भी नहीं है। वैकल्पिक रूप से, आप अपने आंकड़ों की गणना के परिणामों को संग्रहीत करने के लिए monad का उपयोग कर सकते हैं और फिर मोनैड पर getDeadCounter() या getLiveCounter() का उपयोग कर सकते हैं, जैसा कि पहले से ही सुझाए गए हैं।

+0

अच्छा विचार है, लेकिन फ़िल्टर को लागू करने के लिए स्थिर आंतरिक कक्षाओं का उपयोग करें। – Ralph

4
  • आप एक ही विधि में आम कार्यक्षमता को निकालने के लिए और केवल विशिष्ट कार्यक्षमता
  • का उपयोग आप एक निजी विधि बना सकते हैं कोशिश कर सकते हैं उस झंडे के साथ, और इसे दो सार्वजनिक तरीकों से बुलाओ। इस प्रकार आपके सार्वजनिक एपीआई में 'जटिल' विधि हस्ताक्षर नहीं होगा, और आपके पास डुप्लीकेट कोड नहीं होगा
  • एक विधि बनाएं जो दोनों मानों को वापस करे, और प्रत्येक कॉलर (सार्वजनिक विधि) में से कोई एक चुनें।

ऊपर दिए गए उदाहरण में मुझे लगता है कि दूसरे और तीसरे विकल्प अधिक लागू हैं।

1

ऐसा लगता है कि सबसे अधिक अर्थपूर्ण रूप से साफ दृष्टिकोण एक परिणाम ऑब्जेक्ट को वापस करने के लिए होगा जिसमें दोनों मान होते हैं, और कॉलिंग कोड को निकालने दें जो परिणाम ऑब्जेक्ट से इसकी परवाह करता है।

+0

अनुकूलन के लिए +1। अन्यथा मृत और जिंदा पड़ोसियों को पाने के लिए विधि को दो बार बुलाया जाना चाहिए। – khachik

5

आप अपने हस्ताक्षर पर बूलियन पसंद नहीं है, तो आप इसे बिना दो अलग अलग तरीकों, रिफैक्टरिंग private करने के लिए मुख्य एक जोड़ सकते हैं:

int calculateNumOfLiveNeighbors(Cell c, int gen) { 
    return calculateNumOfLiveOrDeadNeighbors(c, gen, true); 
} 
int calculateNumOfDeadNeighbors(Cell c, int gen) { 
    return calculateNumOfLiveOrDeadNeighbors(c, gen, false); 
} 

या

आप कोड सकता है एक परिणाम दोनों कक्षाओं को संग्रहित करने के लिए आउटपुट पैरामीटर के रूप में परिणाम या int array परिणाम; यह आपको कष्टप्रद बूलियन पैरामीटर से छुटकारा पाने देगा।

+1

मैं किसी भी अन्य सुझाव पर सार्वजनिक प्रतिनिधि-विधियों के साथ निजी विधि पसंद करूंगा। – heikkim

1

आईएमओ, यह तथाकथित "प्रत्येक विधि एक चीज करता है" सिद्धांत को चुनिंदा रूप से लागू करने की आवश्यकता है। आपका उदाहरण एक है, यह संभवतः इसे लागू नहीं करना बेहतर है। बल्कि, मैं तो बस विधि कार्यान्वयन थोड़ा आसान बनाने चाहते हैं:

int countNeighbors(Cell c, int gen, boolean countLive) { 
    int x = c.getX(); 
    int y = c.getY(); 
    int counter = 0; 
    for (int i = x - 1; i <= x + 1; i++) { 
     for (int j = y - 1; j <= y + 1; j++) { 
     if (i == x && j == y) 
      continue; 
     CellState s = getCell(i, j).getCellState(gen); 
     if ((countLive && (s == CellState.LIVE || s == CellState.SICK)) || 
      (!countLive && (s == CellState.DEAD || s == CellState.DEAD4GOOD))) { 
      counter++; 
     } 
     } 
    } 
    return counter; 
} 
1

Bozho की तरह कहा: लेकिन लेकिन दूसरी तरह arround में गठबंधन बिंदु 2 और 3:

एक (संभव निजी विधि) बनाएं कि रिटर्न दोनों (जीवित और मृत) और (केवल यदि आप ज्यादातर मामलों में मृत या जीवित अलग की जरूरत है) तो दो तरीकों कि मृत या दोनों लेने परिणाम से बाहर जोड़ें:

DeadLiveCounter calcLiveAndDead(..) {} 
int calcLive(..) { return calcLiveAndDead(..).getLive; } 
int calcDead(..) { return calcLiveAndDead(..).getDead; } 
1

रिफैक्टरिंग का उपयोग करने के मामले में, कुछ चीजें जो आप कर सकते हैं;

  • विधि की प्रतिलिपि बनाएँ और दो संस्करण बनाएं, एक वास्तविक हार्ड कोडित और अन्य झूठी हार्ड कोड वाली। आपके रिफैक्टरिंग टूल आपको इस स्थिर को इनलाइन करने और आवश्यकतानुसार कोड को हटाने में मदद कर सकते हैं।
  • पिछली संगतता के लिए उपर्युक्त सही/गलत विधि को कॉल करने वाली विधि को फिर से बनाएं। फिर आप इस विधि को रेखांकित कर सकते हैं।
0

एक निजी विधि है जो आपके पास वर्तमान में मौजूद सटीक प्रतिलिपि और पेस्ट है। फिर दो नए तरीकों का निर्माण करें, जिनमें से प्रत्येक एक अधिक वर्णनात्मक नाम है जो उचित बुलीयन

1

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

int calculateNumOfLiveOrDeadNeighbors(Cell c, int gen, boolean countLiveOnes) { 
    final int x = c.getX(); 
    final int y = c.getY(); 
    final HashMap<CellState, Integer> counts = new HashMap<CellState, Integer>(); 
    for (CellState state : CellState.values()) 
     counts.put(state, 0); 

    for (int i = x - 1; i < x + 2; i++) { 
     for (int j = y - 1; j < y + 2; j++) { 
      if (i == x && j == y) 
       continue; 
      CellState state = getCell(i, j).getCellState(gen); 
      counts.put(state, counts.get(state) + 1); 
     } 
    } 
    if (countLiveOnes) 
     return counts.get(CellState.LIVE) + counts.get(CellState.SICK); 
    else 
     return counts.get(CellState.DEAD) + counts.get(CellState.DEAD4GOOD); 
} 
संबंधित मुद्दे