क्या एलएसपी का उल्लंघन करना कभी ठीक है?


10

मैं इस प्रश्न का अनुसरण कर रहा हूं , लेकिन मैं अपना ध्यान कोड से एक सिद्धांत पर स्विच कर रहा हूं।

लिस्कोव प्रतिस्थापन सिद्धांत (एलएसपी) की मेरी समझ से , मेरे आधार वर्ग में जो भी तरीके हैं, उन्हें मेरे उपवर्ग में लागू किया जाना चाहिए, और इस पृष्ठ के अनुसार , यदि आप आधार वर्ग में एक विधि को ओवरराइड करते हैं और यह कुछ भी नहीं करता है या फेंकता है अपवाद, आप सिद्धांत के उल्लंघन में हैं।

अब, मेरी समस्या को इस तरह से अभिव्यक्त किया जा सकता है: मेरे पास एक सार है Weapon class, और दो वर्ग हैं, Swordऔर Reloadable। यदि Reloadableकोई विशिष्ट method, बुलाया जाता है Reload(), तो मुझे उस तक पहुंचने के लिए डाउनकास्ट करना होगा method, और, आदर्श रूप से, आप इससे बचना चाहेंगे।

मैं तो का उपयोग करने के बारे में सोचा Strategy Pattern। इस तरह से प्रत्येक हथियार केवल उन कार्यों के बारे में पता था जो यह प्रदर्शन करने में सक्षम है, इसलिए, उदाहरण के लिए, एक Reloadableहथियार, स्पष्ट रूप से पुनः लोड हो सकता है, लेकिन एक Swordभी नहीं हो सकता है और एक के बारे में भी पता नहीं है Reload class/method। जैसा कि मैंने अपने स्टैक ओवरफ्लो पोस्ट में कहा था, मुझे डाउनकास्ट नहीं करना है, और मैं एक List<Weapon>संग्रह को बनाए रख सकता हूं ।

पर एक और मंच , पहले उत्तर अनुमति देने के लिए सुझाव Swordके बारे में पता होना करने के लिए Reloadकुछ भी नहीं करते हैं,। यह वही उत्तर स्टैक ओवरफ्लो पृष्ठ पर दिया गया था जो मैं ऊपर से जुड़ा था।

मैं पूरी तरह से क्यों समझ में नहीं आता। सिद्धांत का उल्लंघन क्यों करें और तलवार को अवगत होने दें Reload, और इसे खाली छोड़ दें? जैसा कि मैंने अपने स्टैक ओवरफ्लो पोस्ट में कहा था, एसपी, मेरी समस्याओं को बहुत हल करता है।

यह एक व्यवहार्य समाधान क्यों नहीं है?

public final Weapon{

    private final String name;
    private final int damage;
    private final List<AttackStrategy> validactions;
    private final List<Actions> standardActions;

    private Weapon(String name, int damage, List<AttackStrategy> standardActions, List<Actions> attacks)
    {
        this.name = name;
        this.damage = damage;
        standardActions = new ArrayList<Actions>(standardActions);
        validAttacks = new ArrayList<AttackStrategy>(validActions);
    }

    public void standardAction(String action){} // -- Can call reload or aim here.  

    public int attack(String action){} // - Call any actions that are attacks. 

    public static Weapon Sword(String name, damage, List<AttackStrategy> standardActions, List<Actions> attacks){
        return new Weapon(name, damage,standardActions, attacks) ;
    }

}

हमला इंटरफेस और कार्यान्वयन:

public interface AttackStrategy{
    void attack(Enemy enemy);
}

public class Shoot implements AttackStrategy {
    public void attack(Enemy enemy){
        //code to shoot
    }
}

public class Strike implements AttackStrategy {
    public void attack(Enemy enemy){
        //code to strike
    }
}

2
आप कर सकते हैं class Weapon { bool supportsReload(); void reload(); }। यदि पुन: लोड करने से पहले समर्थित है तो ग्राहक परीक्षण करेंगे। reloadiff फेंकने के लिए संविदात्मक रूप से परिभाषित किया गया है !supportsReload()। यह एलएसपी iff संचालित कक्षाओं का पालन करता है प्रोटोकॉल मैं सिर्फ उल्लिखित का पालन करें।
usr

3
चाहे आप reload()खाली छोड़ दें या फिर standardActionsजिसमें पुनः लोड क्रिया न हो, बस एक अलग तंत्र है। कोई बुनियादी अंतर नहीं है। आप दोनों कर सकते हैं। => आपका समाधान है व्यवहार्य (जो आपके सवाल था) .; यदि हथियार में रिक्त डिफ़ॉल्ट कार्यान्वयन शामिल है, तो तलवार को पुनः लोड के बारे में जानने की आवश्यकता नहीं है।
usr

27
मैंने इस समस्या को हल करने के लिए विभिन्न तकनीकों के साथ कई तरह की समस्याओं की खोज करते हुए कई लेख लिखे। निष्कर्ष: भाषा के प्रकार प्रणाली में अपने खेल के नियमों को पकड़ने की कोशिश न करेंवस्तुओं में खेल के नियमों को कैप्चर करें जो गेम लॉजिक के स्तर पर नियमों का प्रतिनिधित्व करते हैं और लागू करते हैं, न कि टाइप सिस्टम के स्तर पर । यह मानने का कोई कारण नहीं है कि आप जिस भी प्रकार की प्रणाली का उपयोग कर रहे हैं वह आपके गेम तर्क का प्रतिनिधित्व करने के लिए पर्याप्त परिष्कृत है। ericlippert.com/2015/04/27/wizards-and-warriors-part-one
Eric Lippert

2
@EricLippert - आपके लिंक के लिए धन्यवाद। मैं इस ब्लॉग पर कई बार आया हूं, लेकिन कुछ बिंदुओं ने मुझे काफी समझा है, लेकिन यह आपकी गलती नहीं है। मैं अपने दम पर OOP सीख रहा हूं और SOLID प्रिंसिपलों के सामने आया हूं। पहली बार जब मैं आपके ब्लॉग पर आया, तो मुझे यह बिल्कुल समझ में नहीं आया, लेकिन मैंने थोड़ा और सीखा और आपके ब्लॉग को फिर से पढ़ा, और धीरे-धीरे उन हिस्सों को समझना शुरू कर दिया जो कहा जा रहे थे। एक दिन, मैं पूरी तरह से उस श्रृंखला की हर चीज को समझूंगा। मुझे उम्मीद है: D

6
@ एसआर "यदि यह कुछ भी नहीं करता है या एक अपवाद नहीं फेंकता है, तो आप उल्लंघन में हैं" - मुझे लगता है कि आपने उस लेख से संदेश को गलत तरीके से पढ़ा है। समस्या सीधे तौर पर यह नहीं थी कि सेटेलिट्यूड ने कुछ नहीं किया, यह था कि यह पोस्टकॉन्डिशन को पूरा करने में विफल रहा "पक्षी सेट ऊंचाई पर खींचा जाएगा"। यदि आप "पुनः लोड करना" के पदबंध को परिभाषित करते हैं जैसे "अगर पर्याप्त बारूद उपलब्ध था, तो हथियार फिर से हमला कर सकता है", तो कुछ भी नहीं करना हथियार के लिए पूरी तरह से वैध कार्यान्वयन है जो बारूद का उपयोग नहीं करता है।
सेबस्टियन रेडल

जवाबों:


16

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

  • वंशानुक्रम आधार वर्ग के कार्यान्वयन को विरासत में मिलता था, लेकिन इसका इंटरफ़ेस नहीं। लगभग सभी मामलों में रचना को प्राथमिकता दी जानी चाहिए। जावा जैसी भाषाएं कार्यान्वयन और इंटरफ़ेस की विरासत को अलग नहीं कर सकती हैं, लेकिन उदाहरण के लिए C ++ में privateविरासत है।

  • एक राशि प्रकार / संघ के मॉडल के लिए प्रयुक्त वंशानुक्रम, जैसे: a या Baseतो । आधार प्रकार किसी भी प्रासंगिक इंटरफ़ेस की घोषणा नहीं करता है। इसके उदाहरणों का उपयोग करने के लिए, आपको उन्हें सही ठोस प्रकार में डालना होगा। कास्टिंग सुरक्षित रूप से किया जा सकता है और यह मुद्दा नहीं है। दुर्भाग्यवश, कई ओओपी भाषा बेस क्लास सबटिप को केवल इच्छित उपप्रकारों तक सीमित करने में सक्षम नहीं हैं। यदि बाहरी कोड एक बना सकता है , तो यह मानकर कोड एक या केवल गलत हो सकता है। स्काला इसकी अवधारणा के साथ सुरक्षित रूप से कर सकता है । जावा में, यह तब बनाया जा सकता है जब एक निजी निर्माणकर्ता के साथ एक अमूर्त वर्ग होता है, और घोंसले के स्थिर वर्ग तब आधार से विरासत में मिलते हैं।CaseACaseBCaseCBaseCaseACaseBcase classBase

वास्तविक दुनिया की वस्तुओं की वैचारिक पदानुक्रम जैसी कुछ अवधारणाएँ ऑब्जेक्ट ओरिएंटेड मॉडल में बहुत खराब हैं। विचार जैसे "एक बंदूक एक हथियार है, और एक तलवार एक हथियार है, इसलिए मेरे पास एक Weaponआधार वर्ग होगा जिससे Gunऔर Swordविरासत" भ्रामक हैं: वास्तविक शब्द एक ऐसा संबंध है, जो हमारे मॉडल में इस तरह के रिश्ते का अर्थ नहीं है। एक संबंधित मुद्दा यह है कि ऑब्जेक्ट कई वैचारिक पदानुक्रम से संबंधित हो सकते हैं या रन समय के दौरान अपने पदानुक्रम संबद्धता को बदल सकते हैं, जो कि अधिकांश भाषाएं मॉडल नहीं कर सकती हैं क्योंकि विरासत आमतौर पर प्रति-वर्ग नहीं है, और डिज़ाइन-टाइम रन-टाइम पर परिभाषित होती है।

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

यहां, उपयोगकर्ताओं को attack()हथियारों के साथ और शायद reload()उन्हें आवश्यकता हो सकती है। अगर हमें एक प्रकार की पदानुक्रम बनानी है, तो ये दोनों विधियाँ आधार प्रकार में होनी चाहिए, हालाँकि गैर-पुनः लोड करने योग्य हथियार उस पद्धति को अनदेखा कर सकते हैं और जब कहा जाता है तो कुछ भी नहीं करते हैं। इसलिए बेस क्लास में सामान्य भाग नहीं होते हैं, लेकिन सभी उपवर्गों का संयुक्त इंटरफ़ेस होता है। उपवर्ग उनके इंटरफ़ेस में भिन्न नहीं होते हैं, लेकिन केवल उनके इंटरफ़ेस के कार्यान्वयन में।

यह एक पदानुक्रम बनाने के लिए आवश्यक नहीं है। दो प्रकार Gunऔर Swordपूरी तरह से असंबंधित हो सकते हैं। जबकि एक Gunकर सकते हैं fire()और केवल reload()एक । यदि आपको इन वस्तुओं को बहुरूपिक रूप से प्रबंधित करने की आवश्यकता है, तो आप संबंधित पहलुओं को पकड़ने के लिए एडाप्टर पैटर्न का उपयोग कर सकते हैं। जावा 8 में यह कार्यात्मक इंटरफेस और लैम्ब्डा / विधि संदर्भों के साथ आसानी से संभव है। उदाहरण के लिए आपके पास एक रणनीति हो सकती है जिसके लिए आप आपूर्ति करते हैं या ।Swordstrike()AttackmyGun::fire() -> mySword.strike()

अंत में, कभी-कभी किसी भी उपवर्ग से बचने के लिए समझदार होता है, लेकिन सभी वस्तुओं को एक ही प्रकार के माध्यम से मॉडल करना। यह खेलों में विशेष रूप से प्रासंगिक है क्योंकि कई गेम ऑब्जेक्ट किसी भी पदानुक्रम में अच्छी तरह से फिट नहीं होते हैं, और कई अलग-अलग क्षमताएं हो सकती हैं। उदाहरण के लिए, एक भूमिका निभाने वाले खेल में एक आइटम हो सकता है जो कि एक खोज आइटम है, सुसज्जित होने पर +2 ताकत के साथ आपके आँकड़े को बफ़र करता है, किसी भी नुकसान को अनदेखा करने पर 20% मौका होता है, और हाथापाई का दौरा पड़ता है। या शायद एक पुनः लोड करने योग्य तलवार क्योंकि यह * जादू * है। कौन जानता है कि कहानी को क्या चाहिए।

उस गड़बड़ी के लिए एक वर्ग पदानुक्रम का पता लगाने की कोशिश करने के बजाय, एक वर्ग होना बेहतर है जो विभिन्न क्षमताओं के लिए स्लॉट प्रदान करता है। इन स्लॉट्स को रनटाइम में बदला जा सकता है। प्रत्येक स्लॉट की तरह एक रणनीति / कॉलबैक होगा OnDamageReceivedया Attack। अपने हथियारों के साथ, हम हो सकता है MeleeAttack, RangedAttackऔर Reloadस्लॉट। ये स्लॉट खाली हो सकते हैं, जिस स्थिति में ऑब्जेक्ट यह क्षमता प्रदान नहीं करता है। स्लॉट्स को तब सशर्त रूप से कहा जाता है if (item.attack != null) item.attack.perform():।


एक तरह से एसपी की तरह। स्लॉट खाली क्यों करना पड़ता है? यदि शब्दकोश में क्रिया नहीं है, तो बस कुछ न करें

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

मैं मानता हूं कि वास्तविक दुनिया की वस्तुएं अच्छी तरह से मॉडल नहीं करती हैं। अगर मुझे आपकी पोस्ट समझ में आती है, तो आपका कहना है कि मैं स्ट्रैटेजी पैटर्न का उपयोग कर सकता हूं?

2
@ एसआर हां, किसी न किसी रूप में रणनीति पैटर्न एक समझदार दृष्टिकोण है। संबंधित प्रकार के ऑब्जेक्ट पैटर्न की भी तुलना करें: gameprogrammingpatterns.com/type-object.html
amon

3

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

सभी ने कहा, मैं विशेष रूप से आपके अन्य सवालों के जवाब से सहमत नहीं हूं। होने swordसे विरासत weaponभीषण, अनुभवहीन OO जो हमेशा कोई-op तरीकों या टाइप जांच के सुराग कोड के बारे में बिखरे है।

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


मुझे लगता है कि यह एकदम सही है। मैं एसपी का उपयोग कर सकता हूं, लेकिन वे व्यापार से दूर हैं, बस उनके बारे में पता होना चाहिए। मेरे मन में जो है, उसके लिए मेरा संपादन देखें।

1
Fwiw: एक तलवार में असीम बारूद है: आप इसे बिना पढ़े हमेशा इस्तेमाल कर सकते हैं; reload कुछ नहीं करता है क्योंकि आपके पास शुरू करने के लिए अनंत उपयोग है; एक की सीमा / हाथापाई: यह एक हाथापाई हथियार है। सभी आँकड़ों / कार्यों के बारे में एक तरह से सोचना असंभव नहीं है जो हाथापाई और रंग दोनों के लिए काम करते हैं। फिर भी, जैसा कि मैंने बड़ा किया है मैं इंटरफेस, प्रतियोगिता के पक्ष में कम और कम विरासत का उपयोग करता हूं, और जो भी नाम है वह एकल Weaponवर्ग का उपयोग तलवार और बंदूक के उदाहरण के साथ है।
1897 पर CAD97

भाग्य 2 में Fwiw किसी कारण के लिए बारूद का उपयोग करें!

@ CAD97 - यह इस प्रकार की सोच है जिसे मैंने इस समस्या के बारे में देखा है। अनंत बारूद के साथ तलवार है, इसलिए कोई उतराई नहीं। यह सिर्फ इस समस्या को चारों ओर धकेलता है या छुपाता है। अगर मैं एक ग्रेनेड का परिचय देता हूं, तो क्या होगा? हथगोले में बारूद या गोली नहीं है, और इस तरह के तरीकों के बारे में पता नहीं होना चाहिए।

1
मैं इस पर CAD97 के साथ हूं। और WeaponBuilderरणनीतियों का एक हथियार बनाकर तलवारें और बंदूकें बना सकता है।
क्रिस वॉहर्ट 13

3

बेशक यह एक व्यवहार्य समाधान है; यह सिर्फ एक बहुत बुरा विचार है।

समस्या यह नहीं है यदि आपके पास यह एकल उदाहरण है जहाँ आप अपने बेस क्लास पर पुनः लोड करते हैं। समस्या यह है कि आपको "स्विंग", "शूट" "पैरी", "नॉक", "पॉलिश", "डिसएम्बल", "शार्प" और "क्लब के नुकीले सिरे के नाखूनों को बदलने" की आवश्यकता है। आपके आधार वर्ग पर विधि।

एलएसपी की बात यह है कि आपके शीर्ष स्तर के एल्गोरिदम को काम करने और समझ बनाने की आवश्यकता है। तो अगर मेरे पास इस तरह का कोड है:

if (isEquipped(weapon)) {
   reload();
}

अब अगर यह एक लागू नहीं किया गया अपवाद फेंकता है और आपके कार्यक्रम को दुर्घटनाग्रस्त कर देता है तो यह बहुत बुरा विचार है।

यदि आपका कोड इस तरह दिखता है,

if (canReload(weapon)) {
   reload();
}
else if (canSharpen(weapon)) {
  sharpen();
}
else if (canPollish(weapon)) {
  polish();
}

तब आपका कोड बहुत विशिष्ट गुणों के साथ अव्यवस्थित हो सकता है, जिसका सार 'हथियार' विचार से कोई लेना-देना नहीं है।

हालाँकि यदि आप एक पहले व्यक्ति शूटर को लागू कर रहे हैं और आपके सभी हथियार शूट कर सकते हैं / उस एक चाकू को छोड़कर फिर से लोड कर सकते हैं (तो आपके विशिष्ट संदर्भ में) तो यह बहुत मायने रखता है कि आपके चाकू को फिर से लोड करने से कुछ नहीं होगा क्योंकि यह अपवाद और बाधाओं है विशिष्ट गुणों के साथ आपके आधार वर्ग का क्लॉट होना कम है।

अपडेट: अमूर्त मामले / शर्तों के बारे में सोचने की कोशिश करें। उदाहरण के लिए, शायद हर हथियार में एक "तैयार" क्रिया होती है जो बंदूकों के लिए फिर से लोड होती है और तलवारों के लिए एक नीचे की ओर होती है।


मान लें कि मेरे पास एक आंतरिक हथियार शब्दकोश है जो हथियारों के लिए कार्रवाई करता है, और जब उपयोगकर्ता "रीलोड" में गुजरता है, तो वह शब्दकोश की जांच करता है, पूर्व, हथियारएक्शंस.कंटेनसीके (कार्रवाई) यदि ऐसा है, तो इसके साथ जुड़े ऑब्जेक्ट को पकड़ो, और करें यह। एक हथियार वर्ग के बजाय कई बयानों के साथ

ऊपर संपादित देखें। यह वही है जो मैंने एसपी का उपयोग करते समय ध्यान में रखा था

0

स्पष्ट रूप से यह ठीक है यदि आप बेस क्लास के एक उदाहरण को बदलने के इरादे से उप-वर्ग नहीं बनाते हैं, लेकिन यदि आप आधार वर्ग का उपयोग कार्यक्षमता के सुविधाजनक भंडार के रूप में करते हैं।

अब यह एक अच्छा विचार है या नहीं, यह बहुत ही बहस का विषय है, लेकिन अगर आपने कभी भी बेसकलैस के लिए उपवर्ग को प्रतिस्थापित नहीं किया है, तो यह तथ्य नहीं है कि यह काम नहीं करता है। आपको समस्याएं हो सकती हैं, लेकिन एलएसपी इस मामले में समस्या नहीं है।


0

एलएसपी अच्छा है क्योंकि यह कॉलिंग कोड को चिंता करने की अनुमति नहीं देता है कि कक्षा कैसे काम करती है।

जैसे। मैं अपने बैटलचेक पर लगाए गए सभी हथियारों पर Weapon.Attack () कॉल कर सकता हूं और चिंता नहीं करता कि उनमें से कुछ अपवाद छोड़ सकते हैं और मेरे गेम को क्रैश कर सकते हैं।

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

इसका आसान उपाय यह है कि, मुझे नहीं लगता कि आपको प्रदर्शन के बारे में अधिक चिंता करने की जरूरत है, आपका हर फ्रेम में ऐसा नहीं होने जा रहा है।

वैकल्पिक रूप से आप अपनी वास्तुकला को आश्वस्त कर सकते हैं और विचार कर सकते हैं कि अमूर्त में सभी हथियार पुनः लोड करने योग्य हैं, और कुछ हथियारों को बस फिर से लोड करने की आवश्यकता नहीं है।

तब आप बंदूक के लिए कक्षा का विस्तार नहीं कर रहे हैं, या एलएसपी का उल्लंघन कर रहे हैं।

लेकिन यह समस्याग्रस्त दीर्घकालिक है क्योंकि आप अधिक विशेष मामलों को सोचने के लिए बाध्य हैं, Gun.SafteyOn (), Sword.WipeOffBlood () आदि और यदि आप उन सभी को हथियार में डालते हैं, तो आपके पास एक सुपर जटिल सामान्य आधार वर्ग है जिसे आप रखते हैं बदल रहा है।

संपादित करें: रणनीति पैटर्न क्यों खराब है (tm)

यह नहीं है, लेकिन सेटअप, प्रदर्शन और समग्र कोड पर विचार करें।

मुझे कहीं न कहीं कुछ कॉन्फिगर करना होगा जो मुझे बताता है कि एक बंदूक फिर से लोड हो सकती है। जब मैं किसी हथियार को तुरंत भेज देता हूं, तो मुझे यह पढ़ना होगा कि कॉन्फ़िगर और गतिशील रूप से सभी तरीकों को जोड़ दें, जांचें कि कोई डुप्लिकेट नाम आदि नहीं हैं

जब मैं किसी विधि को कॉल करता हूं, तो मुझे उस कार्य सूची के माध्यम से लूप करना पड़ता है और यह देखने के लिए एक स्ट्रिंग मिलान करना है कि किसे कॉल करना है।

जब मैं कोड संकलित करता हूं और "अटैक" के बजाय Weapon.Do ("atack") को कॉल करता हूं, तो मुझे संकलन पर कोई त्रुटि नहीं मिलेगी।

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


मुझे लगता है कि एसपी सब संभाल सकता है (ऊपर संपादित देखें), बंदूक होती SafteyOn()और Swordहोती wipeOffBlood()। प्रत्येक हथियार अन्य तरीकों के बारे में पता नहीं है (और वे नहीं होना चाहिए)

एसपी ठीक है, लेकिन बिना सुरक्षा के डाउनकास्टिंग के बराबर है। मुझे लगता है कि मैं थोड़े अलग सवाल का जवाब दे रहा था, मुझे अपडेट करने दें
इवान

2
अपने आप में रणनीति पैटर्न किसी सूची या शब्दकोश में रणनीति के गतिशील रूप को नहीं देखता है। यानी दोनों weapon.do("attack")और प्रकार-सुरक्षित weapon.attack.perform()रणनीति पैटर्न के उदाहरण हो सकते हैं। किसी कॉन्फ़िगरेशन फ़ाइल से ऑब्जेक्ट को कॉन्फ़िगर करते समय केवल नाम से रणनीतियाँ देखना आवश्यक है, हालांकि प्रतिबिंब का उपयोग करना समान रूप से सुरक्षित होगा।
आमोन

इस स्थिति में काम नहीं करेंगे क्योंकि दो अलग-अलग कार्रवाई के हमले और फिर से लोड होते हैं, जो आपको कुछ उपयोगकर्ता इनपुट के लिए बाध्य करने की आवश्यकता होती है
इवान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.