2009-06-23 14 views
50

मैं डिजाइन सिद्धांतों को डिजाइन और सीखने के लिए नया हूं।आयत से स्क्वायर ले रहा है लिस्कोव के प्रतिस्थापन सिद्धांत का उल्लंघन?

यह कहता है कि आयताकार से वर्ग प्राप्त करना लिस्कोव के प्रतिस्थापन सिद्धांत का उल्लंघन का एक उत्कृष्ट उदाहरण है।

यदि ऐसा है, तो सही डिजाइन क्या होना चाहिए?

उत्तर

52

मेरा मानना ​​है कि तर्क कुछ इस तरह है:

मान लीजिए कि आप एक विधि है कि एक आयत इसकी चौड़ाई स्वीकार करता है और समायोजित कर देता है करते हैं:

public void SetWidth(Rectangle rect, int width) 
{ 
    rect.Width = width; 
} 

यह पूरी तरह से उचित होना चाहिए, यह देखते हुए क्या एक आयत है , यह मानने के लिए कि यह परीक्षण पास होगा:

Rectangle rect = new Rectangle(50, 20); // width, height 

SetWidth(rect, 100); 

Assert.AreEqual(20, rect.Height); 

... क्योंकि आयताकार की चौड़ाई बदलना इसकी ऊंचाई को प्रभावित नहीं करता है।

हालांकि, मान लीजिए कि आपने आयत से एक नई स्क्वायर क्लास ली है। परिभाषा के अनुसार, एक वर्ग की ऊंचाई और चौड़ाई हमेशा बराबर होती है। आइए फिर से परीक्षण की कोशिश करें:

Rectangle rect = new Square(20); // both width and height 

SetWidth(rect, 100); 

Assert.AreEqual(20, rect.Height); 

वह परीक्षण विफल हो जाएगा, क्योंकि वर्ग की चौड़ाई 100 तक सेट करने से इसकी ऊंचाई भी बदल जाएगी।

इस प्रकार, लिस्कोव के प्रतिस्थापन सिद्धांत का उल्लंघन आयत से स्क्वायर प्राप्त करके किया जाता है।

"आइस-ए" नियम "असली दुनिया" (एक वर्ग निश्चित रूप से आयत का एक प्रकार है) में समझ में आता है, लेकिन हमेशा सॉफ्टवेयर डिजाइन की दुनिया में नहीं।

संपादित

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

+2

दूसरा उदाहरण, क्या 50 के लिए जोर परीक्षण करना चाहिए? बीटीडब्लू, "असली दुनिया" में एक वर्ग या तो परिवर्तनीय नहीं है (एक पृष्ठ पर चित्रित होता है) या जब बल लागू होता है (यह रबड़ से बना होता है), वास्तविक दुनिया में आईओओ एक वस्तु कर सकता है गतिशील रूप से कुछ प्रकार बदलें जो हम प्रोग्रामिंग भाषाओं में बहुत अच्छी तरह से मॉडल नहीं करते हैं। – AnthonyWJones

+1

ओह, दूसरे उदाहरण पर अच्छी तरह से देखा गया। परीक्षण सही है - ctor पैरामीटर गलत है। क्लिपबोर्ड विरासत बग! मैं इसे ठीक कर दूंगा। –

-3

यह बहुत आसान है :) अधिक 'आधार' वर्ग (व्युत्पन्न श्रृंखला में पहला) सबसे सामान्य होना चाहिए।

उदाहरण के लिए आकार -> आयताकार -> स्क्वायर।

यहां एक वर्ग एक आयत का एक विशेष मामला है (बाध्य आयामों के साथ) और एक आयताकार आकार का एक विशेष मामला है।

एक और तरीका कहा - "एक है" परीक्षण का उपयोग करें। एक स्क्वायर एक आयताकार है। लेकिन एक आयत हमेशा एक वर्ग नहीं है।

+3

आपने "लिस्कोव प्रतिस्थापन सिद्धांत" के संबंध में प्रश्न में इस बिंदु को याद किया है। Http://www.objectmentor.com/resources/articles/lsp.pdf देखें जो बताता है कि आयताकार-> वर्ग के मामले के लिए इस सिद्धांत के संबंध में 'एक' परीक्षण पर्याप्त नहीं है। जवाब इतना आसान नहीं है। (मैंने आपको नीचे चिह्नित नहीं किया)। –

2

मान लीजिए कि हमारे पास वर्ग आयताकार (सादगी के लिए सार्वजनिक) गुण चौड़ाई, ऊंचाई के साथ कक्षा आयत है। हम उन दो गुणों को बदल सकते हैं: r.width = 1, r.height = 2।
अब हम एक स्क्वायर is_a आयताकार कहते हैं। लेकिन हालांकि दावा है कि "एक वर्ग एक आयत की तरह व्यवहार करेगा" हम एक वर्ग वस्तु पर .width = 1 और .height = 2 सेट नहीं कर सकते हैं (यदि आप ऊंचाई निर्धारित करते हैं और इसके विपरीत) आपकी कक्षा शायद चौड़ाई समायोजित करती है। तो कम से कम एक मामला है जहां स्क्वायर प्रकार का एक वस्तु आयताकार की तरह व्यवहार नहीं करता है और इसलिए आप उन्हें (पूरी तरह से) प्रतिस्थापित नहीं कर सकते हैं।

61

उत्तर उत्परिवर्तन पर निर्भर करता है।यदि आपका आयताकार और वर्ग वर्ग अपरिवर्तनीय हैं, तो Square वास्तव में Rectangle का एक उप प्रकार है और यह दूसरे से पहले प्राप्त करने के लिए बिल्कुल ठीक है। अन्यथा, Rectangle और Square दोनों कोई म्यूटेटर के साथ IRectangle का पर्दाफाश कर सकते हैं, लेकिन दूसरे से एक प्राप्त करना गलत है क्योंकि न तो प्रकार ठीक से दूसरे का उप प्रकार है।

+9

+1, वाईईपी! मैं इसे 20+ सालों से कह रहा हूं और शायद ही कोई सुन रहा है ... –

+1

उत्परिवर्तन के साथ अच्छा बिंदु। – Gishu

+0

समझदार। मुझे लगता है कि आप यह कहकर थोड़ा आगे सामान्यीकृत कर सकते हैं कि "ए बी का एक उप प्रकार है" बी द्वारा खुलासा किया गया सार्वजनिक इंटरफ़ेस पर निर्भर करता है। एक छोटा इंटरफ़ेस (उदाहरण के लिए म्यूटेटर की कमी वाला एक इंटरफ़ेस) उस राशि को कम करता है जो आप कर सकते हैं "करते हैं" उस प्रकार या इसके उपप्रकारों की ठोस वस्तुओं के साथ, लेकिन आपको उप प्रकार के लिए अधिक अवसर प्रदान करता है। –

3

मैं इस बात से सहमत नहीं हूं कि आयत से वर्ग प्राप्त करने के लिए आवश्यक रूप से एलएसपी का उल्लंघन होता है।

मैट के उदाहरण में, यदि आपके पास कोड है जो चौड़ाई और ऊंचाई पर निर्भर करता है, तो यह वास्तव में एलएसपी का उल्लंघन करता है।

हालांकि, यदि आप किसी भी धारणा को तोड़ने के बिना अपने कोड में हर जगह एक वर्ग के लिए एक आयत को प्रतिस्थापित कर सकते हैं तो आप एलएसपी का उल्लंघन नहीं कर रहे हैं।

तो यह वास्तव में में आपके समाधान में अमूर्त आयताकार का अर्थ है।

+1

यह सही है, लेकिन स्क्वायर क्लास होने के लिए यह व्यर्थ है जब तक कि आप प्रोग्राम में अपने इनवेरिएंट का उपयोग न करें :) –

+0

मैं कल्पना कर सकता हूं कि एक कोड बेस है जो छवि आयताकारों पर काम करता है। यदि आयताकार वर्ग होने पर आपको प्रदर्शन अनुकूलन के लिए एक विचार मिलता है। तो हाँ, आप वर्ग में आंतरिक रूप से चौड़ाई/ऊंचाई आविष्कार का उपयोग कर रहे हैं, लेकिन यह बाहरी दुनिया के लिए अदृश्य है (केवल तभी जब चौड़ाई और ऊंचाई की ऑर्थोगोनैलिटी पर कोड में कोई धारणा नहीं बनाई जाती है)। –

+0

मैं सहमत हूं, लेकिन यह उपरोक्त मैट द्वारा सुझाए गए * आयत * आविष्कारों का उपयोग करके किसी और के मामले को कवर नहीं करता है। जब मैंने पहली टिप्पणी लिखी तो मैंने यह नहीं देखा। –

1

मेरा मानना ​​है कि ओओडी/ओओपी तकनीक वास्तविक दुनिया का प्रतिनिधित्व करने के लिए सॉफ़्टवेयर को सक्षम करने के लिए मौजूद है। वास्तविक दुनिया में एक वर्ग एक आयताकार होता है जिसमें बराबर पक्ष होते हैं। वर्ग केवल एक वर्ग है क्योंकि इसमें बराबर पक्ष हैं, न कि क्योंकि यह एक वर्ग बनने का फैसला करता है। इसलिए, ओओ कार्यक्रम से निपटने की जरूरत है। बेशक, अगर ऑब्जेक्ट को चालू करने वाला दिनचर्या वर्ग बनना चाहता है, तो यह लंबाई की संपत्ति और चौड़ाई संपत्ति को उसी राशि के बराबर निर्दिष्ट कर सकता है। यदि ऑब्जेक्ट का उपयोग करने वाले प्रोग्राम को बाद में पता होना चाहिए कि यह वर्ग है, तो इसे केवल पूछने की आवश्यकता है। ऑब्जेक्ट में "स्क्वायर" नामक केवल पढ़ने वाली बुलीयन संपत्ति हो सकती है। जब कॉलिंग दिनचर्या इसे आमंत्रित करती है, तो वस्तु वापस आ सकती है (लंबाई = चौड़ाई)। अब यह मामला हो सकता है भले ही आयताकार वस्तु अपरिवर्तनीय हो। इसके अलावा, अगर आयत वास्तव में अपरिवर्तनीय है, स्क्वायर संपत्ति का मूल्य कन्स्ट्रक्टर में सेट किया जा सकता है और इसके साथ किया जा सकता है। फिर यह एक मुद्दा क्यों है? एलएसपी को उप-वस्तुओं को लागू करने के लिए अपरिवर्तनीय होने की आवश्यकता होती है और आयत के उप-वस्तु होने के वर्ग को अक्सर इसके उल्लंघन के उदाहरण के रूप में उपयोग किया जाता है। लेकिन यह अच्छा डिज़ाइन प्रतीत नहीं होता है क्योंकि जब उपयोग की नियमितता ऑब्जेक्ट को "objSquare" के रूप में आमंत्रित करती है, तो उसे इसके आंतरिक विवरण को जानना चाहिए। क्या यह बेहतर नहीं होगा अगर यह परवाह नहीं करता कि आयत वर्ग था या नहीं? और ऐसा इसलिए होगा क्योंकि आयत के तरीकों पर ध्यान दिए बिना सही होगा। क्या एलएसपी का उल्लंघन होने का एक बेहतर उदाहरण है?

एक और सवाल: एक वस्तु अपरिवर्तनीय कैसे बनाई जाती है? क्या कोई "अपरिवर्तनीय" संपत्ति है जिसे तत्काल पर सेट किया जा सकता है?

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

-1

समस्या यह है कि वर्णित किया जा रहा है वास्तव में एक "प्रकार" नहीं बल्कि एक संचयी उभरती संपत्ति है।

आपके पास वास्तव में एक चतुर्भुज है और दोनों "स्क्वायरनेस" और "आयताकारता" केवल कोण और पक्षों के गुणों से प्राप्त उभरती कलाकृतियों हैं।

"स्क्वायर" (या यहां तक ​​कि आयत) की पूरी अवधारणा एक दूसरे के संबंध में वस्तु के गुणों के संग्रह का एक सार प्रस्तुतिकरण है और वस्तु में सवाल है, न कि वस्तु के प्रकार में ।

यह वह जगह है जहां एक टाइपलेस भाषा के संदर्भ में समस्या की सोच में मदद मिल सकती है, क्योंकि यह ऐसा नहीं है जो यह निर्धारित करता है कि यह "वर्ग" है लेकिन ऑब्जेक्ट की वास्तविक गुण यह निर्धारित करती है कि यह "वर्ग" है या नहीं।

मुझे लगता है कि अगर आप अमूर्तता भी लेना चाहते हैं तो आप यह भी नहीं कहेंगे कि आपके पास चतुर्भुज है लेकिन आपके पास बहुभुज या यहां तक ​​कि केवल एक आकार है।

3

मैं इस समस्या के साथ एक बहुत हाल ही में संघर्ष कर दिया गया है और सोचा था कि मैं रिंग में मेरी टोपी जोड़ेंगे:

public class Rectangle { 

    protected int height;  
    protected int width; 

    public Rectangle (int height, int width) { 
     this.height = height; 
     this.width = width; 
    } 

    public int computeArea() { return this.height * this.width; } 
    public int getHeight() { return this.height; } 
    public int getWidth() { return this.width; } 

} 

public class Square extends Rectangle { 

    public Square (int sideLength) { 
     super(sideLength, sideLength); 
    } 

} 

public class ResizableRectangle extends Rectangle { 

    public ResizableRectangle (int height, int width) { 
     super(height, width); 
    } 

    public void setHeight (int height) { this.height = height; } 
    public void setWidth (int width) { this.width = width; } 

} 

सूचना आखिरी वर्ग, ResizableRectangle। "Resizableness" को उप-वर्ग में ले जाकर, हम वास्तव में हमारे मॉडल में सुधार करते समय कोड पुनः उपयोग करते हैं। इस तरह के बारे में सोचें: एक वर्ग को छोड़कर एक वर्ग को स्वतंत्र रूप से आकार में नहीं बदला जा सकता है, जबकि गैर स्क्वायर आयताकार कर सकते हैं। सभी आयताकारों का आकार बदला जा सकता है, क्योंकि वर्ग एक आयताकार है (और इसकी "पहचान" को बनाए रखने के दौरान इसे स्वतंत्र रूप से आकार में नहीं बदला जा सकता है)। (o_O) तो यह आधार Rectangle कक्षा बनाने के लिए समझ में आता है जो आकार बदलने योग्य नहीं है, क्योंकि यह की कुछ अतिरिक्त संपत्ति है आयताकार।

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

  • कोई संबंधित समस्या नहीं^_^