2012-05-28 6 views
13

कोड परिसर में Steve McConnell's के समान स्थिति में मैं एक स्थिति में हूं। केवल यही कि मेरी समस्या वाहनों पर आधारित है और ट्राइक उस पर होता है जब कानून कारों की श्रेणी में पड़ता है। कारों के पास अब तक चार पहियों थे। किसी भी तरह से मेरा डोमेन अनावश्यक रूप से जटिल है, इसलिए नीचे बिल्लियों के उदाहरण के साथ रहना आसान है।मैं लिस्कोव प्रतिस्थापन सिद्धांत (एलएसपी) तोड़ने से कैसे बच सकता हूं?

वर्गों है कि एक नियमित ओवरराइड और व्युत्पन्न दिनचर्या यह आमतौर पर आधार वर्ग के डिजाइन में एक त्रुटि दर्शाता है अंदर कुछ नहीं कर से सतर्क रहें। उदाहरण के लिए, मान लीजिए कि आपके पास क्लास कैट और रूटीन स्क्रैच() है और मान लीजिए कि आपको अंततः पता चलता है कि कुछ बिल्लियों को घोषित किया गया है और स्क्रैच नहीं कर सकते हैं। आप स्क्रैचलेस कैट नामक बिल्ली से प्राप्त वर्ग बनाने के लिए लुभाने वाले हो सकते हैं और कुछ भी करने के लिए स्क्रैच() दिनचर्या को ओवरराइड कर सकते हैं। यह दृष्टिकोण कई समस्याओं को प्रस्तुत करता है:

यह अपने इंटरफेस के अर्थशास्त्र को बदलकर बिल्ली कक्षा में प्रस्तुत अमूर्तता (इंटरफ़ेस अनुबंध) का उल्लंघन करता है।

जब आप इसे अन्य व्युत्पन्न कक्षाओं तक बढ़ाते हैं तो यह दृष्टिकोण तुरंत नियंत्रण से बाहर हो जाता है। क्या होता है जब आपको पूंछ के बिना बिल्ली मिलती है? या बिल्ली जो चूहों को पकड़ नहीं पाती है? या एक बिल्ली जो दूध नहीं पीती है? आखिरकार आप व्युत्पन्न कक्षाओं जैसे स्क्रैचलेसटाइलेस मिसलेस मिल्ककेलेस कैट के साथ समाप्त हो जाएंगे।

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

इस समस्या को ठीक करने के लिए स्थान बेस क्लास में नहीं है, लेकिन मूल बिल्ली वर्ग में है। एक पंजे वर्ग बनाएं और बिल्लियों वर्ग के भीतर रखें। मूल समस्या यह धारणा थी कि सभी बिल्लियों खरोंच, इसलिए गंतव्य पर उस समस्या को ठीक करें, बस इसे गंतव्य पर बैंडिंग करने के बजाय।

उपरोक्त अपनी महान पुस्तक के पाठ के मुताबिक। बाद बुरा

जनक क्लास अब वह किसी अन्य वर्ग Claws बनाने का सुझाव सार

public abstract class Cat { 
    public void scratch() { 
     System.out.println("I can scratch"); 
    } 
} 

व्युत्पन्न वर्ग होने के लिए

public class ScratchlessCat extends Cat { 
    @Override 
    public void scratch() { 
     // do nothing 
    } 
} 

नहीं है, लेकिन मैं कैसे समझ में नहीं आता कर सकते हैं मैं ScratchlessCat#Scratch की आवश्यकता से बचने के लिए इस कक्षा का उपयोग करता हूं।

+2

के रूप में बिल्ली उदाहरण LSP का एक अच्छा उदाहरण है व्यवस्थित करने के लिए एक DefenseMechanism वर्ग को परिभाषित कर सकते हैं। एलएसपी के बारे में सीखने में मुझे आश्चर्य हुआ कि एसओ और अन्य साइटों पर कितने खराब उदाहरण हैं और कितनी गलतफहमी है। – SteveT

उत्तर

8

आप अभी भी एक scratch() विधि होता है, लेकिन यह व्युत्पन्न वर्ग द्वारा ओवरराइड नहीं किया जाएगा:

public class Cat { 
    Claw claw_; 
    public Cat(Claw claw) {claw = claw_;} 
    public final void scratch() { 
    if (claw_ != null) { 
     claw_.scratch(this); 
    } 
    } 
} 

यह आपको निहित Claw वस्तु को खरोंच तर्क को सौंपने के लिए अनुमति देता है, अगर वर्तमान (और नहीं खरोंच अगर कोई पंजे नहीं हैं)। बिल्ली से व्युत्पन्न कक्षाओं में इस मामले में कोई बात नहीं है कि कैसे खरोंच करना है, इसलिए क्षमताओं के आधार पर छाया पदानुक्रम बनाने की कोई आवश्यकता नहीं है।

इसके अलावा, क्योंकि व्युत्पन्न कक्षाएं विधि कार्यान्वयन को नहीं बदल सकती हैं, इसलिए बेस क्लास इंटरफ़ेस में scratch() विधि के इच्छित अर्थशास्त्र को तोड़ने में कोई समस्या नहीं है।

यदि आप इसे चरम पर ले जाते हैं, तो आप पाएंगे कि आपके पास बहुत सी कक्षाएं हैं और कई व्युत्पन्न नहीं हैं - अधिकांश तर्क रचनात्मक वस्तुओं को सौंपा गया है, जो व्युत्पन्न कक्षाओं को सौंपा नहीं गया है।

11

कि सभी बिल्लियों के पंजे नहीं हैं और खरोंच करने में सक्षम हैं एक बड़ी सुराग है कि Cat को अपने एपीआई में scratch विधि को परिभाषित नहीं करना चाहिए। पहला कदम यह विचार करना है कि आपने पहली जगह scratch क्यों परिभाषित किया था। शायद बिल्लियों खरोंच अगर वे हमला कर सकते हैं; अगर नहीं तो वे उसका पीछा करते हैं या भाग जाते हैं।

public class Cat extends Animal { 
    private Claws claws; 

    public void onAttacked(Animal attacker) { 
     if (claws != null) { 
      claws.scratch(attacker); 
     } 
     else { 
      // Assumes all cats can hiss. 
      // This may also be untrue and you need Voicebox. 
      // Rinse and repeat. 
      hiss(); 
     } 
    } 
} 

अब आप किसी अन्य के लिए किसी भी Cat उपवर्ग स्थानापन्न कर सकते हैं और इसे सही ढंग चाहे या नहीं यह पंजे, इस पर निर्भर व्यवहार करेगा। आप विभिन्न गढ़ ऐसे Scratch, Hiss, Bite, आदि

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