2008-10-05 16 views
12

मैंने this explanation on Wikipedia, विशेष रूप से सी ++ नमूना देखा है, और केवल 3 वर्गों को परिभाषित करने, उदाहरण बनाने और उन्हें कॉल करने के बीच अंतर को पहचानने में असफल रहा है, और वह उदाहरण। मैंने जो देखा वह सिर्फ दो अन्य वर्गों को प्रक्रिया में रख रहा था और यह नहीं देख सकता कि लाभ कहाँ होगा। अब मुझे यकीन है कि मुझे कुछ स्पष्ट याद आ रहा है (पेड़ों के लिए लकड़ी) - क्या कोई इसे एक वास्तविक असली दुनिया के उदाहरण का उपयोग करके समझा सकता है?रणनीति पैटर्न का उपयोग करने में लाभ कहां है?


मैं क्या जवाब अब तक से कर सकते हैं, मुझे लगता है ऐसा करने का सिर्फ एक अधिक जटिल तरीके होने के लिए:

have an abstract class: MoveAlong with a virtual method: DoIt() 
have class Car inherit from MoveAlong, 
    implementing DoIt() { ..start-car-and-drive..} 
have class HorseCart inherit from MoveAlong, 
    implementing DoIt() { ..hit-horse..} 
have class Bicycle inherit from MoveAlong, 
    implementing DoIt() { ..pedal..} 
now I can call any function taking MoveAlong as parm 
passing any of the three classes and call DoIt 
Isn't this what Strategy intents? (just simpler?) 

[संपादित करें अद्यतन] समारोह मैं का उल्लेख उपरोक्त को दूसरी कक्षा के साथ प्रतिस्थापित किया गया है जिसमें MoveAlong विशेषता होगी जो इस नई कक्षा में लागू एल्गोरिदम के आधार पर आवश्यकता के अनुसार सेट की गई है। (क्या स्वीकार किए जाते हैं जवाब में बताया गया है की तरह।)


[संपादित करें अद्यतन] निष्कर्ष

रणनीति पैटर्न यह का उपयोग करता है है है, लेकिन मैं KISS में एक मजबूत आस्तिक हूँ, और जाते हैं अधिक सरल और कम obfuscatory तकनीक के लिए। अधिकतर जब से मैं आसानी से रखरखाव योग्य कोड पर गुजरना चाहता हूं (और 'मैं सबसे अधिक संभावना है जो परिवर्तन करना है!)।

+0

"नहीं है यह रणनीति का इरादा क्या है? (बस इतना आसान?) "<- बहुत कुछ, सिवाय इसके कि आप अपनी कक्षा का संदर्भ देते हैं और दूसरी कक्षा को इसे कॉल करने की आवश्यकता होती है, जबकि दूसरी कक्षा केवल यह जानती है कि इसमें एक मूवऑलॉन्ग है। यह उन चीजों में से एक है जो एक टीम की स्थिति में अधिक उपयोगी है। – Gerald

+0

हाय जेराल्ड मुझे लगता है कि आपका उदाहरण रणनीति पैटर्न का एक बुरा उदाहरण है। हां यह एक रणनीति है लेकिन आपके मामले में रणनीति पैटर्न को लागू करने से उप-वर्ग होना बेहतर होगा। मुझे यकीन है कि मार्टियन घड़ी की पृथ्वी घड़ी की तुलना में अलग व्यवहार होगा, इसलिए घड़ी वर्ग को उप-वर्ग के लायक है। – RWendi

+0

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

उत्तर

19

बिंदु जो रनटाइम के दौरान में खामियों को दूर किया जा सकता है वर्गों में एल्गोरिदम अलग करने के लिए है। उदाहरण के लिए, मान लें कि आपके पास एक ऐसा एप्लिकेशन है जिसमें घड़ी शामिल है। कई अलग-अलग तरीके हैं जिन्हें आप घड़ी खींच सकते हैं, लेकिन अधिकांश भाग के लिए अंतर्निहित कार्यक्षमता वही है।तो तुम एक घड़ी प्रदर्शन इंटरफ़ेस बना सकते हैं:

class IClockDisplay 
{ 
    public: 
     virtual void Display(int hour, int minute, int second) = 0; 
}; 

तो फिर आप अपने घड़ी वर्ग कि एक टाइमर को झुका और एक बार घड़ी प्रदर्शन अद्यतन करता है प्रति सेकंड है।

class Clock 
{ 
    protected: 
     IClockDisplay* mDisplay; 
     int mHour; 
     int mMinute; 
     int mSecond; 

    public: 
     Clock(IClockDisplay* display) 
     { 
      mDisplay = display; 
     } 

     void Start(); // initiate the timer 

     void OnTimer() 
     { 
     mDisplay->Display(mHour, mMinute, mSecond); 
     } 

     void ChangeDisplay(IClockDisplay* display) 
     { 
      mDisplay = display; 
     } 
}; 

फिर कार्यावधि में आप उचित प्रदर्शन वर्ग के साथ अपनी घड़ी का दृष्टांत: तो आप की तरह कुछ होगा। यानी आप ClockDisplayDigital, ClockDisplayAnalog, ClockDisplayMartian को आईसीलॉक डिस्प्ले इंटरफ़ेस को लागू करने वाले सभी को प्राप्त कर सकते हैं।

तो आप बाद में अपने घड़ी वर्ग के साथ गड़बड़ किए बिना एक नई कक्षा बनाकर और बिना किसी तरीके के ओवरराइड किए बिना किसी भी प्रकार का नया घड़ी प्रदर्शन जोड़ सकते हैं जो बनाए रखने और डीबग करने के लिए गन्दा हो सकता है।

+0

तो प्रश्न में मेरे विचार-कोड में, फंक्शन के रूप में MoveAlong को ले जाने वाला फ़ंक्शन आपके क्लॉक-क्लास के बराबर के साथ प्रतिस्थापित किया जाता है? – slashmais

+0

यह सिर्फ मुझे मारा कि यह कमान पैटर्न के समान है जहां आप कमांड के कन्स्ट्रक्टर पर एक एक्शन में पास करते हैं। –

+0

एक कमान * पर एक एक्शन ऑब्जेक्ट पास कर रहा है * रणनीति पैटर्न का उपयोग कर रहा है। –

1

विकिपीडिया उदाहरण में, उन उदाहरणों को एक ऐसे कार्य में पारित किया जा सकता है, जिसकी देखभाल करने की आवश्यकता नहीं है कि वे कौन से वर्ग हैं। फ़ंक्शन बस ऑब्जेक्ट पर execute पर कॉल करता है, और पता है कि सही चीज होगी।

रणनीति पैटर्न का एक सामान्य उदाहरण यह है कि यूनिक्स में फ़ाइलें कैसे काम करती हैं। एक फाइल डिस्क्रिप्टर को देखते हुए, आप इसे पढ़ सकते हैं, इसे लिख सकते हैं, इसे खोज सकते हैं, इसे देख सकते हैं, ioctl एस को भेज सकते हैं, आदि, यह जानने के बिना कि क्या आप फ़ाइल, निर्देशिका, पाइप, सॉकेट, उपकरण, इत्यादि। (निश्चित रूप से कुछ ऑपरेशन, जैसे कि पाइप और सॉकेट पर काम नहीं करते हैं, लेकिन पढ़ते हैं और लिखते हैं इन मामलों में ठीक काम करेंगे।)

इसका मतलब है कि आप इन सभी को संभालने के लिए जेनेरिक कोड लिख सकते हैं विभिन्न प्रकार की "फाइलें", फाइल बनाम निर्देशिकाओं से निपटने के लिए अलग कोड लिखने के बिना, यूनिक्स कर्नेल सही कोड पर कॉल को प्रतिनिधि देने का ख्याल रखता है।

अब, यह कर्नेल कोड में उपयोग की जाने वाली रणनीति पैटर्न है, लेकिन आपने यह निर्दिष्ट नहीं किया है कि यह उपयोगकर्ता कोड होना चाहिए, केवल वास्तविक दुनिया उदाहरण होना चाहिए। :-)

+0

कोड को बनाए रखते हैं "एक ऐसे फ़ंक्शन में पारित किया गया है जिस पर ध्यान नहीं दिया जाता है कि उन वर्गों का कौन सा वर्ग संबंधित है" - ऐसा लगता है कि आपने और पेड़ जोड़े हैं ;-)। वर्चुअल फ़ंक्शंस/पॉलिमॉर्फिज्म/जेनेरिक विधियों कक्षाओं से यह अलग कैसे है? – slashmais

+1

यह _is_ वर्चुअल फ़ंक्शंस। रणनीति पैटर्न, मेरी समझ में, कंक्रीट वर्गों की बजाय कार्यक्षमता तक पहुंचने के लिए इंटरफेस (जावा अर्थ में) का उपयोग करके आभासी कार्यों का एक बहुत ही विशिष्ट उपयोग है। –

10

जावा में आप एक सिफर इनपुट धारा उपयोग करती हैं इसलिए तरह डिक्रिप्ट करने के लिए:

String path = ... ; 
InputStream = new CipherInputStream(new FileInputStream(path), ???); 

लेकिन सिफर धारा क्या एन्क्रिप्शन एल्गोरिथ्म आप उपयोग करना चाहते का ज्ञान नहीं या ब्लॉक आकार, गद्दी रणनीति आदि है ... नए एल्गोरिदम हर समय जोड़े जाएंगे ताकि उन्हें हार्डकोडिंग व्यावहारिक न हो। इसके बजाय हम एक सिफर रणनीति वस्तु में पास यह बताने के लिए कि डिक्रिप्शन प्रदर्शन करने के लिए ...

String path = ... ; 
Cipher strategy = ... ; 
InputStream = new CipherInputStream(new FileInputStream(path), strategy); 

सामान्य तौर पर आप रणनीति पैटर्न किसी भी समय का उपयोग आप किसी भी वस्तु है कि जानता है क्या यह करने की जरूरत है लेकिन यह करने के लिए नहीं।स्विंग में एक और अच्छा उदाहरण लेआउट मैनेजर है, हालांकि उस मामले में यह काफी काम नहीं करता है, एक मनोरंजक चित्रण के लिए Totally GridBag देखें।

एनबी: यहां काम पर दो पैटर्न हैं, क्योंकि धाराओं में धाराओं की रैपिंग Decorator का एक उदाहरण है।

+1

ने अभी 'पूरी तरह से ग्रिडबैग' बिट देखा - मैं उससे संबंधित हो सकता हूं। lol – slashmais

2

यह डिज़ाइन पैटर्न कक्षाओं में एल्गोरिदम को एन्सेप्लेट करता है।

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

उदाहरण के लिए, किसी ऐसे एप्लिकेशन की कल्पना करें जिसे किसी फ़ाइल को फ़ाइल में सहेजने की आवश्यकता हो; छवि को विभिन्न प्रारूपों में सहेजा जा सकता है (पीएनजी, जेपीजी ...)। एन्कोडिंग एल्गोरिदम सभी को समान इंटरफ़ेस साझा करने वाले विभिन्न वर्गों में लागू किया जाएगा। क्लाइंट क्लास उपयोगकर्ता वरीयता के आधार पर एक का चयन करेगा।

4

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

  • आप रनटाइम पर रणनीति बदल सकते हैं:

    रणनीति दृष्टिकोण कुछ लाभ प्रदान करता है

  • एक मुख्य वर्ग एक से अधिक रणनीतियों का उपयोग कर सकता है जो आपको कई तरीकों से पुन: संयोजित करने की अनुमति देता है। एक वर्ग पर विचार करें जो एक पेड़ पर चलता है और प्रत्येक नोड और वर्तमान परिणाम के आधार पर एक फ़ंक्शन का मूल्यांकन करता है। आपके पास पैदल चलने की रणनीति हो सकती है (गहराई-प्रथम या चौड़ाई-पहले) और गणना रणनीति (कुछ मज़ेदार - यानी 'सकारात्मक संख्याएं' या 'योग')। यदि आप रणनीतियों का उपयोग नहीं करते हैं, तो आपको चलने/गणना के प्रत्येक संयोजन के लिए उप-वर्ग लागू करने की आवश्यकता होगी।
  • कोड को संशोधित करने या रणनीति को समझने के पूरे मुख्य उद्देश्य को समझने के लिए आप की आवश्यकता नहीं है के रूप में बनाए रखने के लिए आसान है

दोष यह है कि कई मामलों में, रणनीति पैटर्न एक overkill है - स्विच/मामले ऑपरेटर है यहां किसी कारण से। सरल नियंत्रण प्रवाह विवरण (स्विच/केस या अगर) के साथ शुरू करने पर विचार करें, केवल तभी कक्षा पदानुक्रम में आवश्यक कदम और यदि आपके पास परिवर्तनशीलता के एक से अधिक आयाम हैं, तो इसके बाहर रणनीतियों को निकालें। फंक्शन पॉइंटर्स इस निरंतरता के बीच में कहीं गिरते हैं।

अनुशंसित पढ़ने:

5

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

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

2

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

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

0

रणनीति पैटर्न सरल विचार पर काम करता है यानी "विरासत पर रचना का अनुकूलन" ताकि रणनीति/एल्गोरिदम रन टाइम पर बदला जा सके। उदाहरण के लिए चलिए एक उदाहरण लें जहां हमें इसके प्रकार के आधार पर विभिन्न संदेशों को एन्क्रिप्ट करना होगा उदा। MailMessage, ChatMessage आदि

class CEncryptor 
{ 
    virtual void encrypt() = 0; 
    virtual void decrypt() = 0; 
}; 
class CMessage 
{ 
private: 
    shared_ptr<CEncryptor> m_pcEncryptor; 
public: 
    virtual void send() = 0; 

    virtual void receive() = 0; 

    void setEncryptor(cost shared_ptr<Encryptor>& arg_pcEncryptor) 
    { 
     m_pcEncryptor = arg_pcEncryptor; 
    } 

    void performEncryption() 
    { 
     m_pcEncryptor->encrypt(); 
    } 
}; 
रनटाइम पर

अब आप अलग अलग संदेश CMessage से (CMailMessage की तरह: सार्वजनिक CMessage) विरासत में मिला दृष्टांत कर सकते हैं विभिन्न encryptors साथ (CDESEncryptor की तरह: सार्वजनिक CEncryptor)

CMessage *ptr = new CMailMessage(); 
ptr->setEncryptor(new CDESEncrypto()); 
ptr->performEncryption(); 
संबंधित मुद्दे