2010-03-31 12 views
5

लगता है कि मैं इस "डेमेटर के कानून" चीज़ पर पढ़ रहा हूं, और यह (और सामान्य रूप से शुद्ध "रैपर" वर्ग) विरोधी पैटर्न होने लगते हैं। कहा तरीकोंरैपर/डेमेटर का कानून एक विरोधी पैटर्न

class ScreenSpaceEffects1 { 
    private FluidSimulator _fluidDynamics; 
    public FluidSimulator getFluidSimulator() { return _fluidDynamics; } 
} 

class ScreenSpaceEffects2 { 
    private FluidSimulator _fluidDynamics; 
    public void resetFluidSimulation() { _fluidDynamics.reset(); } 
} 

और तरीकों कॉल करने के लिए:

callingMethod() { 
    effects1.getFluidSimulator().reset(); // Version 1 
    effects2.resetFluidSimulation();  // Version 2 
} 

पहले लाल पर, संस्करण 2 लगता है

class FluidSimulator { 
    void reset() { /* ... */ } 
} 

अब अन्य वर्ग की दो अलग-अलग कार्यान्वयन पर विचार करें: एक कार्यान्वयन वर्ग पर विचार करें थोड़ा आसान, और "डेमेटर के नियम" का पालन करता है, फू के कार्यान्वयन इत्यादि को छुपाता है, लेकिन यह FluidSimulator में ScreenSpaceEffects में कोई भी परिवर्तन करता है। उदाहरण के लिए, अगर एक पैरामीटर रीसेट करने के लिए जोड़ा है, तो हमने:

class FluidSimulator { 
    void reset(bool recreateRenderTargets) { /* ... */ } 
} 

class ScreenSpaceEffects1 { 
    private FluidSimulator _fluidDynamics; 
    public FluidSimulator getFluidSimulator() { return _fluidDynamics; } 
} 

class ScreenSpaceEffects2 { 
    private FluidSimulator _fluidDynamics; 
    public void resetFluidSimulation(bool recreateRenderTargets) { _fluidDynamics.reset(recreateRenderTargets); } 
} 

callingMethod() { 
    effects1.getFluidSimulator().reset(false); // Version 1 
    effects2.resetFluidSimulation(false);  // Version 2 
} 

दोनों संस्करणों में, callingMethod को बदलने की आवश्यकता है, लेकिन संस्करण 2 में, ScreenSpaceEffects भी की जरूरत है परिवर्तित करने की। क्या कोई रैपर/मुखौटा (एडाप्टर के अपवाद के साथ या बाहरी एपीआई लपेटने या आंतरिक को उजागर करने के लाभ के साथ) का लाभ समझा सकता है।

संपादित करें: कई वास्तविक उदाहरणों में से एक जिसके लिए मैं एक छोटे उदाहरण के बजाय इसमें भाग गया।

+0

क्या आपका मतलब है "संस्करण 2 थोड़ा सा आसान लगता है"? –

+0

हाँ, क्षमा करें, –

+0

बदल जाएगा संस्करण 1 डेमेटर के नियम का पालन नहीं करता है। गलत टाइप? – Corwin

उत्तर

13

मुख्य अंतर यह है कि संस्करण 1 में, Bar अमूर्तता के प्रदाता के रूप में, आपके पास Foo का खुलासा नहीं है पर आपका कोई नियंत्रण नहीं है। Foo में कोई भी बदलाव आपके ग्राहकों के सामने आ जाएगा, और उन्हें इसके साथ सहन करना होगा।

संस्करण 2 के साथ, अमूर्त Bar के प्रदाता के रूप में, आप यह तय कर सकते हैं कि आप विकास और कैसे उजागर करना चाहते हैं। यह केवल Bar अमूर्तता पर निर्भर करेगा, और Foo नहीं है। आपके उदाहरण में, आपके Bar अमूर्तता पहले से ही जानी जा सकती है कि कौन सा पूर्णांक तर्क के रूप में पास हो सकता है, और इस प्रकार आप अपने उपयोगकर्ताओं को पारदर्शी रूप से Foo के नए संस्करण का उपयोग करने में सक्षम नहीं होंगे, बिना किसी बदलाव के।

मान लीजिए अब फू विकसित होता है, और doSomething पर किसी भी कॉल से पहले उपयोगकर्ता को foo.init() पर कॉल करने की आवश्यकता होती है। संस्करण 1 के साथ, बार के सभी उपयोगकर्ताओं को यह देखने की आवश्यकता होगी कि फू बदल गया है, और उनके कोड को अनुकूलित करें। संस्करण 2 के साथ, केवल Bar को बदला जाना है, इसकी doSomething यदि आवश्यक हो तो init पर कॉल करना। यह कम कीड़े (केवल अमूर्त Bar जानते हैं और अमूर्त Foo और वर्गों के बीच कम युग्मन समझने के लिए है के लेखक के लिए कई, callingMethod (वास्तविक जीवन में, वहाँ कर सकते हैं होता है।

+0

मुझे विश्वास नहीं है कि यह अतिरिक्त जटिलता के लायक है (विशेष रूप से यदि कक्षाएं पहले से ही युग्मित हैं), लेकिन वैसे भी उत्तर के लिए धन्यवाद :-)। –

+0

लगभग किसी भी समय कुछ बदलता है, कुछ और बदलना होगा। सबसे अच्छा कोई भी ऐसा कर सकता है कि सबकुछ व्यवस्थित करने का प्रयास करें ताकि जो हिस्सों में स्थिर रहना पड़े, वे स्थिर रह सकेंगे, भले ही चीजें बदलने की संभावना हो, ऐसा करें। दिए गए प्रत्येक डिज़ाइन कुछ प्रकार के संभावित भावी एपीआई परिवर्तनों को दूसरे से अधिक आसानी से समायोजित करने में सक्षम होंगे; कौन सा डिज़ाइन बेहतर है कुछ मापनों पर निर्भर करता है कि कैसे विभिन्न संभावित भविष्य में बदलावों की संभावनाओं का न्याय करता है। – supercat

2

यह स्पष्ट रूप से एक कृत्रिम उदाहरण है। कई वास्तविक मामलों में callingMethods) आनंद से अनजान रह सकते हैं कि Foo.do कुछ बदल गया है, क्योंकि बार इसे इन्सुलेट करता है। उदाहरण के लिए, यदि मैं एक स्थिर प्रिंटिंग एपीआई का उपयोग करता हूं, तो मुझे चमकदार प्रिंटिंग के लिए समर्थन जोड़ने वाले मेरे प्रिंटर के फर्मवेयर के बारे में चिंतित होने की आवश्यकता नहीं है। मेरा मौजूदा काला -और-व्हाइट प्रिंटिंग कोड काम करता रहता है। मुझे लगता है कि आप इसे "एडाप्टर" के तहत समूहित करेंगे, जो मुझे लगता है कि यह आपके से अधिक आम है।

आप सही हैं कि कभी-कभी कॉलिंग मोड बदलना चाहिए एड भी लेकिन जब डेमेटर का कानून सही तरीके से उपयोग किया जाता है, तो यह केवल दुर्लभ रूप से होता है, आमतौर पर नई कार्यक्षमता का लाभ उठाने के लिए (जैसा कि एक नए इंटरफेस से अलग है)।

संपादित करें: ऐसा लगता है कि कॉलिंग मोड को परवाह नहीं है कि लक्ष्य प्रस्तुत करना है या नहीं (मुझे लगता है कि यह प्रदर्शन v. सटीकता का सवाल है)। आखिरकार, "हमें छोटी क्षमता के बारे में भूल जाना चाहिए, लगभग 97% समय" (Knuth) कहें। तो ScreenSpaceEffects2 resetFluidSimulation(bool) विधि जोड़ सकता है, लेकिन resetFluidSimulation() दृश्यों के पीछे _fluidDynamics.reset(true) पर कॉल करके काम कर रहा है (कॉलिंग मोड में परिवर्तन किए बिना)।

+0

दरअसल, मैं इस सवाल से पूछ रहा हूं क्योंकि यह मेरे शौक परियोजना –

+1

में कई बार आया है क्या हुआ है? हो सकता है कि यह एक वास्तविक उदाहरण है, सभी 'फू' और 'बार' के बजाय? –

+1

एक असली उदाहरण जोड़ा गया। –

2

सवाल यह है कि callingMethod() को यह जानने की आवश्यकता है कि प्रतिपादन तालिकाओं को फिर से बनाना है या नहीं?

मान लीजिए callingMethod() के कुछ निष्पादन को प्रतिपादन तालिकाओं को फिर से बनाने की आवश्यकता नहीं है या नहीं। उस स्थिति में आप एक नई विधि के साथ रैपर का विस्तार करते हैं। फिर आपको केवल callingMethod() के उचित उदाहरणों से नई विधि को कॉल करने की आवश्यकता है।

class ScreenSpaceEffects2 { 
    private FluidSimulator _fluidDynamics; 
    public void resetFluidSimulation() { _fluidDynamics.reset(false); } 
    public void resetFluidSimulationWithRecreate() { _fluidDynamics.reset(true); } 
} 

वैकल्पिक रूप से callingMethod() में पुन: बनाने के लिए कहीं और पूरी तरह से संबंधित हो सकता है निर्णय ...

class ScreenSpaceEffects2 { 
    private FluidSimulator _fluidDynamics; 
    public void resetFluidSimulation() { 
      _fluidDynamics.reset(someRuleEngine.getRecreateRenderTables()); } 
} 

... whch मामले में कुछ भी बिल्कुल परिवर्तित है।

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