2010-09-03 8 views
11

क्या यह कोई कोड गंध देता है या सोलिड सिद्धांतों का उल्लंघन करता है?क्या यह विधि SOLID का उल्लंघन करती है या कोड गंध है?

public string Summarize() 
{ 
IList<IDisplayable> displayableItems = getAllDisplayableItems(); 
StringBuilder summary = new StringBuilder(); 

foreach(IDisplayable item in displayableItems) 
{ 
    if(item is Human) 
     summary.Append("The person is " + item.GetInfo()); 

    else if(item is Animal) 
     summary.Append("The animal is " + item.GetInfo()); 

    else if(item is Building) 
     summary.Append("The building is " + item.GetInfo()); 

    else if(item is Machine) 
     summary.Append("The machine is " + item.GetInfo()); 
} 

return summary.ToString(); 
} 

आप देख सकते हैं, मेरे संक्षेप में प्रस्तुत करना(), इस तरह के मानव, पशु के रूप में कार्यान्वयन वर्गों से जुड़ा हुआ है आदि

यह गंध है? क्या मैं एलएसपी का उल्लंघन कर रहा हूं? कोई अन्य ठोस सिद्धांत?

उत्तर

1

ओपी से this answer पर टिप्पणी को देखते हुए नहीं है, मुझे लगता है कि सबसे अच्छा तरीका IList<IDisplayable> displayableItems जो containsHumans() और containsAnimals() तरह के तरीकों को बदलने के लिए है एक कस्टम कंटेनर वर्ग बनाने के लिए ताकि आप को भावुक गैर संपुटित कर सकते हैं हो सकता है पॉलीमोर्फिक कोड एक ही स्थान पर और तर्क को Summarize() फ़ंक्शन साफ़ रखें।

class MyCollection : List<IDisplayable> 
{ 
    public bool containsHumans() 
    { 
     foreach (IDisplayable item in this) 
     { 
      if (item is Human) 
       return true; 
     } 

     return false; 
    } 

    // likewise for containsAnimals(), etc 
} 

public string Summarize() 
{ 
    MyCollection displayableItems = getAllDisplayableItems(); 
    StringBuilder summary = new StringBuilder(); 

    if (displayableItems.containsHumans() && !displayableItems.containsAnimals()) 
    { 
     // do human-only logic here 
    } 
    else if (!displayableItems.containsHumans() && displayableItems.containsAnimals()) 
    { 
     // do animal-only logic here 
    } 
    else 
    { 
     // do logic for both here 
    } 

    return summary.ToString(); 
} 

बेशक मेरा उदाहरण अत्यधिक सरल और समेकित है।उदाहरण के लिए, या तो Summarize() में तर्क के हिस्से के रूप में यदि/अन्य कथन, या शायद पूरे ब्लॉक के आस-पास, तो आप displayableItems संग्रह पर फिर से शुरू करना चाहेंगे। इसके अलावा, यदि आप Add() और Remove()MyCollection में ओवरराइड करते हैं तो आपको बेहतर प्रदर्शन मिलेगा और उन्हें ऑब्जेक्ट के प्रकार की जांच करें और ध्वज सेट करें, इसलिए आपका containsHumans() फ़ंक्शन (और अन्य) बस ध्वज की स्थिति वापस कर सकता है और नहीं जब भी उन्हें बुलाया जाता है तो संग्रह को फिर से शुरू करने के लिए।

+0

आपके उत्तर के लिए धन्यवाद, लेकिन मैं पूरी तरह से तकनीकीता को समझ नहीं रहा हूं, तो क्या आप मुझे इसका उदाहरण दे सकते हैं? :) फिर से धन्यवाद, यह वही हो सकता है जो मुझे चाहिए। मुझे बस इसका एक उदाहरण देखने की जरूरत है। –

+0

हम्म ... क्या यह तथ्य है कि आपने इसे स्वीकार किया है इसका मतलब है कि आपको एक उदाहरण की आवश्यकता नहीं है? मुझे एक प्रदान करने की कोशिश करने में खुशी होगी, लेकिन मुझे पूरा यकीन नहीं है कि कौन सा हिस्सा आपको भ्रम पैदा कर रहा है। यदि आप अधिक विशिष्ट हो सकते हैं, तो मैं इसे आज़मा दूंगा। – rmeador

+0

मैंने इसे एक उत्तर के रूप में स्वीकार किया, क्योंकि उसने मेरे विशिष्ट प्रश्न का उत्तर दिया। मैं इस पर आधारित समाधान पर काम कर रहा हूं। मुझे यह सुनिश्चित करने के लिए एक उदाहरण की आवश्यकता है कि मैं तकनीकीता को समझूं। जस्टिन का जवाब नीचे बहुत विस्तृत और सहायक था, इसलिए इसके जैसा कुछ भी शानदार होगा। –

20

मैं एक छोटे से कुछ ...

अपनी कक्षाओं सभी IDisplayable लागू करते हैं तो वे एक के लिए खुद को प्रदर्शित करने के लिए अपने स्वयं के तर्क को लागू करना चाहिए गंध आती है। उस स्थिति में आपके पाश कुछ अधिक स्वच्छ करने के लिए बदल जाएगा:

public interface IDisplayable 
{ 
    void Display(); 
    string GetInfo(); 
} 

public class Human : IDisplayable 
{ 
    public void Display() { return String.Format("The person is {0}", 
     GetInfo()); 

    // Rest of Implementation 
} 

public class Animal : IDisplayable 
{ 
    public void Display() { return String.Format("The animal is {0}", 
     GetInfo()); 

    // Rest of Implementation 
} 

public class Building : IDisplayable 
{ 
    public void Display() { return String.Format("The building is {0}", 
     GetInfo()); 

    // Rest of Implementation 
} 

public class Machine : IDisplayable 
{ 
    public void Display() { return String.Format("The machine is {0}", 
     GetInfo()); 

    // Rest of Implementation 
} 

तो फिर तुम अधिक स्वच्छ कुछ करने के लिए अपने पाश बदल सकते हैं (और वर्गों को अपने स्वयं के प्रदर्शन तर्क लागू करने के लिए अनुमति देते हैं):

foreach(IDisplayable item in displayableItems) 
    summary.Append(item.Display()); 
+0

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

+2

@SP - हां। यदि आप कंक्रीट कार्यान्वयन के लिए Summarize() का व्यवहार कर रहे हैं, तो आप IDISplayable इंटरफ़ेस के माध्यम से पॉलीमोर्फिक रूप से ऑब्जेक्ट्स का इलाज करने के लाभों को वास्तव में अस्वीकार कर रहे हैं। अगर संक्षेप में व्यवहार को बदलने की जरूरत है, तो इसे IDISplayable इंटरफ़ेस के सदस्यों के माध्यम से ऐसा करना चाहिए। –

+0

@SP, शायद आप जो कुछ करना चाहते हैं उसे समझाएं। उदाहरण के लिए, IDisplayable में 1000 कार्यान्वयन प्रकार हो सकते हैं, लेकिन आप केवल उनमें से 5 की परवाह करते हैं। –

5

की तरह लगता है IDisplayable प्रदर्शन नाम के लिए एक विधि होनी चाहिए ताकि आप की तरह

summary.Append("The " + item.displayName() + " is " + item.getInfo()); 
+0

स्टैक ओवरफ्लो में आपका स्वागत है, अपने प्रवास का आनंद लें और अपनी वेट्रेस को टिपना याद रखें। जब भी संभव हो तो उचित कोड स्वरूपण का उपयोग करने का प्रयास करें! –

1

कुछ करने के लिए है कि विधि कम कर सकते हैं कैसे के बारे में:

summary.Append("The " + item.getType() + " is " + item.GetInfo()); 
3

हां।

क्यों नहीं हर वर्ग IDisplayable से एक विधि को लागू कि अपने प्रकार पता चलता है:

interface IDisplayable 
{ 
    void GetInfo(); 
    public string Info; 
} 
class Human : IDisplayable 
{ 
    public string Info 
    { 
    get 
    { 
     return "";//your info here 
    } 
    set; 
    } 

    public void GetInfo() 
    { 
     Console.WriteLine("The person is " + Info) 
    } 
} 

तो बस इस प्रकार अपने विधि कॉल:

foreach(IDisplayable item in displayableItems) 
{ 
    Console.WriteLine(item.GetInfo()); 
} 
1

एक न्यूनतम यह LSP और ओपन का उल्लंघन करती है पर बंद सिद्धांत। ताकि संक्षेप सिर्फ कॉल कर सकते हैं

summary.Append(string.Format("The {0} is {1}", item.Description, item.GetInfo())); 

यह भी, प्रतिबिंब के माध्यम से हल किया जा सकता है क्योंकि आप केवल क्लास के नाम हो रही है

समाधान, IDisplayable इंटरफ़ेस करने के लिए एक Description संपत्ति है।

बेहतर समाधान विधि से IDisplayableInfo जैसा कुछ वापस करना है। ओसीपी को संरक्षित रखने में मदद के लिए यह एक विस्तारशील बिंदु होगा।

+0

क्या आप संक्षेप में समझा सकते हैं कि यह एलएसपी का उल्लंघन क्यों करता है? मैं समझता हूं कि यह ओसीपी का उल्लंघन करता है। क्या होगा अगर मेरे पास सारांश() में अतिरिक्त तर्क है कि यह जांचने के लिए कि किस तरह के कार्यान्वयन कक्षाएं हैं? –

+0

@SP यहां एक सूक्ष्म भेद हो सकता है। सिद्धांत कहने का एक आम तरीका यह है कि जिन कार्यों को बेस क्लास के पॉइंटर्स या संदर्भों का उपयोग किया जाता है, वे इसे जानने के बिना व्युत्पन्न कक्षाओं की वस्तुओं का उपयोग करने में सक्षम होना चाहिए। 'इसे जानने के बिना "क्या मतलब है? एक अर्थ में आपकी विधि 'IDisplayable' के किसी भी कार्यान्वयन के साथ काम करती है - यह संकलित करेगी और अपवाद नहीं फेंक देगी। एक और अर्थ में, यह काम नहीं करता है क्योंकि इसे 'आईडीआईप्लेबल' के साथ सार्थक कुछ करने के लिए कार्यान्वयन को "जानना" है। – Jay

0

यदि आप आईडीआईप्लेबल या क्लास कार्यान्वयन को संशोधित नहीं कर सकते हैं और आप .NET 3.5 का उपयोग कर रहे हैं या बाद में आप एक्सटेंशन विधियों का उपयोग कर सकते हैं। लेकिन उस कि ज्यादा बेहतर

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