रणनीति पैटर्न का वास्तविक विश्व उदाहरण


94

मैं OCP प्रिंसिपल के बारे में पढ़ रहा हूं और इसे पूरा करने के लिए रणनीति पैटर्न का उपयोग कैसे करें।

मैं एक-दो लोगों को इसके बारे में बताने और समझाने की कोशिश करने जा रहा था, लेकिन इसका एकमात्र उदाहरण मैं सोच सकता हूँ कि "आदेश" किस स्थिति के आधार पर विभिन्न मान्यता वर्गों का उपयोग कर रहा है।

मैंने लेखों के एक जोड़े को ऑनलाइन पढ़ा है, लेकिन ये आमतौर पर रणनीति का उपयोग करने के लिए एक वास्तविक कारण का वर्णन नहीं करते हैं, जैसे रिपोर्ट / बिल / सत्यापन आदि उत्पन्न करना ...

क्या कोई वास्तविक दुनिया के उदाहरण हैं जहां आपको लगता है कि एक रणनीति पैटर्न आम है?

जवाबों:


99

इस बारे में क्या:

आपको किसी फ़ाइल को एन्क्रिप्ट करना होगा।

छोटी फ़ाइलों के लिए, आप "मेमोरी में" रणनीति का उपयोग कर सकते हैं, जहां पूरी फ़ाइल को पढ़ने और मेमोरी में रखा जाता है (चलो फ़ाइलों के लिए कहते हैं <1 gb)

बड़ी फ़ाइलों के लिए, आप एक और रणनीति का उपयोग कर सकते हैं, जहां फ़ाइल के कुछ हिस्सों को मेमोरी में पढ़ा जाता है और आंशिक एन्क्रिप्टेड परिणाम tmp फ़ाइलों में संग्रहीत किए जाते हैं।

ये एक ही कार्य के लिए दो अलग-अलग रणनीतियाँ हो सकती हैं।

ग्राहक कोड समान दिखेगा:

 File file = getFile();
 Cipher c = CipherFactory.getCipher( file.size() );
 c.performAction();



// implementations:
interface  Cipher  {
     public void performAction();
}

class InMemoryCipherStrategy implements Cipher { 
         public void performAction() {
             // load in byte[] ....
         }
}

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             // swapt partial results to file.
         }

}

     Cipher c = CipherFactory.getCipher( file.size() );

सिफर के लिए सही रणनीति उदाहरण लौटाएगा।

आशा है कि ये आपकी मदद करेगा।

(मुझे यह भी नहीं पता कि सिफर सही शब्द है: P)


8
क्या आपका उदाहरण फैक्टरी पैटर्न नहीं है? इसके अलावा, मुझे लगता है कि यह C # उदाहरण के लिए काम नहीं करेगा। आपकी "getCipher ()" विधि एक स्थिर विधि है, लेकिन C # में आप एक इंटरफ़ेस पर एक स्थिर विधि को परिभाषित नहीं कर सकते हैं (न ही जावा में मुझे लगता है लेकिन इसके लिए मुझे यकीन नहीं है)।
फ्रांसीसी जनता

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

ऑस्कर प्वाइंट पर जोड़ने के लिए, बिना फैक्ट्री के यह बिना फैक्ट्री बनाई जा सकती है Cipher C =null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c= SwaptToDiskCipher (); }
अभिजीत मजुमदार

@FrenchData से सहमत हैं। जबकि एक महान उदाहरण की मौजूदगी CipherFactoryउन लोगों को भ्रमित कर सकती है जो रणनीति पैटर्न से परिचित नहीं हैं।
user487772

1
फैक्टरी पैटर्न रचनात्मक के बारे में है, रणनीति व्यवहार के बारे में है। थोड़ा अलग अधिकार है?
nhoxbypass

61

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

सामान जो इस श्रेणी में आता है:

  • सॉर्टिंग: हम इन नंबरों को सॉर्ट करना चाहते हैं, लेकिन हम नहीं जानते कि क्या हम ब्रिकॉर्ट, बबलर्ट या किसी अन्य छँटाई का उपयोग करने वाले हैं

  • सत्यापन: हमें "कुछ नियम" के अनुसार वस्तुओं की जांच करने की आवश्यकता है, लेकिन यह अभी तक स्पष्ट नहीं है कि वह नियम क्या होगा, और हम नए के बारे में सोच सकते हैं।

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

  • जानकारी संग्रहीत करना: हम चाहते हैं कि एप्लिकेशन डेटाबेस को जानकारी संग्रहीत करे, लेकिन बाद में किसी फ़ाइल को सहेजने या वेबकॉल करने में सक्षम होने की आवश्यकता हो सकती है

  • आउटपुट: हमें X को एक सादे स्ट्रिंग के रूप में आउटपुट करने की आवश्यकता है, लेकिन बाद में एक CSV, XML, JSON, आदि हो सकते हैं।


उदाहरण

मेरे पास एक परियोजना है जहां उपयोगकर्ता डेटाबेस में लोगों को उत्पाद प्रदान कर सकते हैं। किसी व्यक्ति को किसी उत्पाद का यह असाइनमेंट एक स्थिति है जो या तो "स्वीकृत" या "अस्वीकृत" है, जो कुछ व्यावसायिक नियमों पर निर्भर है। उदाहरण के लिए: यदि कोई उपयोगकर्ता किसी निश्चित आयु वाले व्यक्ति को कोई उत्पाद प्रदान करता है, तो उसकी स्थिति को अस्वीकार कर दिया जाना चाहिए; यदि आइटम में दो क्षेत्रों के बीच का अंतर 50 से बड़ा है, तो यह स्थिति अस्वीकृत है, आदि।

अब, विकास के समय में ये व्यावसायिक नियम पूरी तरह से स्पष्ट नहीं हैं, और नए नियम किसी भी समय सामने आ सकते हैं। स्ट्रैगेटी-पैटर्न की शक्ति यह है कि मैंने एक नियम बनाया, जिसे आईआरयूल्स की एक सूची दी गई।

public interface IRule {
    bool IsApproved(Assignment assignment); 
 }

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

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

public OvertimeRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Timesheet >= 40)
        {
            return false;
        }
        return true;
    }
}

public InternRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Title == "Intern")
        {
            return false;
        }
        return true;
    }
}

आप देखते हैं कि आपको यदि स्टेटमेंट या कोड को जोड़ना या हटाना नहीं पड़ता है, तो बस एक नया नियम-वर्ग बनाएं जो IRUle इंटरफ़ेस को लागू करता है और ज़रूरत पड़ने पर उन्हें स्विच करता है।


एक और महान उदाहरण: http://www.asp.net/mvc/pluralsight पर स्कॉट एलेन की वीडियो श्रृंखला जहां वह एप्लिकेशन के यूनिट-टेस्ट भाग में रणनीति पैटर्न का उपयोग करता है

वह एक वेबसाइट बनाता है जिसमें एक पेज होता है जो लोकप्रियता के आधार पर आइटम प्रदर्शित करता है। हालाँकि "लोकप्रिय" कई चीजें हो सकती हैं (अधिकांश दृश्य, अधिकांश ग्राहक, निर्माण तिथि, अधिकांश गतिविधि, कम से कम टिप्पणियां, आदि), और मामले में प्रबंधन अभी तक नहीं जानता है कि कैसे ऑर्डर करना है, और अलग-अलग प्रयोग करना चाहते हैं। एक बाद की तारीख में आदेश। आप एक ऑर्डर विधि के साथ एक इंटरफ़ेस (IOrderAl एल्गोरिथम या कुछ) बनाते हैं, और ऑर्डर-ऑब्जेक्ट को IOrderAl एल्गोरिथमम इंटरफ़ेस के ठोस कार्यान्वयन के लिए ऑर्डर करने देते हैं। आप एक "CommentOrderer", "ActivOrderer", आदि बना सकते हैं ... और नई आवश्यकताएं पूरी होने पर इन्हें स्विच करें।


मुझे पता है कि यह सवाल के दायरे से बाहर है लेकिन आगे क्या आता है? InternRuleअब हमारे पास यह है लेकिन हम कैसे ट्रिगर कर रहे हैं OvertimeRule? हम यह कैसे सुनिश्चित करें कि OvertimeRule.IsApprovedअब जो भी तर्क कहा जाता है वह भी कॉल करता है InternRule.IsApproved?
स्पेंसर रूपर्ट

13

मुख्य नोट:

  1. रणनीति व्यवहार डिजाइन पैटर्न है। इसका उपयोग एल्गोरिदम के परिवार के बीच स्विच करने के लिए किया जाता है।

  2. इस पैटर्न में एक सार रणनीति इंटरफ़ेस और उस इंटरफ़ेस के कई ठोस रणनीति कार्यान्वयन ( एल्गोरिदम ) शामिल हैं।

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

विकिपीडिया से यूएमएल आरेख

यहां छवि विवरण दर्ज करें

एक वास्तविक शब्द उदाहरण: एयरलाइंस कुछ महीनों (जुलाई-दिसंबर) के दौरान छूट प्रदान करता है । आपके पास एक किराया मॉड्यूल हो सकता है, जो महीने की संख्या के आधार पर मूल्य निर्धारण के विकल्प तय करता है।

एक साधारण उदाहरण देखें। इस उदाहरण को ऑन-लाइन रिटेलिंग अनुप्रयोगों के लिए बढ़ाया जा सकता है, जो खरीदारी के सामानों को विशेष दिनों / खुश घंटों पर आसानी से छूट प्रदान करता है।

import java.util.*;

/* Interface for Strategy */
interface OfferStrategy {
    public String getName();
    public double getDiscountPercentage();
}
/* Concrete implementation of base Strategy */
class NoDiscountStrategy implements OfferStrategy{
    public String getName(){
        return this.getClass().getName();
    }
    public double getDiscountPercentage(){
        return 0;
    }
}
/* Concrete implementation of base Strategy */
class QuarterDiscountStrategy implements OfferStrategy{
    public String getName(){
        return this.getClass().getName();
    }
    public double getDiscountPercentage(){
        return 0.25;
    }
}
/* Context is optional. But if it is present, it acts as single point of contact
   for client. 

   Multiple uses of Context
   1. It can populate data to execute an operation of strategy
   2. It can take independent decision on Strategy creation. 
   3. In absence of Context, client should be aware of concrete strategies. Context acts a wrapper and hides internals
   4. Code re-factoring will become easy
*/
class StrategyContext {
    double price; // price for some item or air ticket etc.
    Map<String,OfferStrategy> strategyContext = new HashMap<String,OfferStrategy>();
    StrategyContext(double price){
        this.price= price;
        strategyContext.put(NoDiscountStrategy.class.getName(),new NoDiscountStrategy());
        strategyContext.put(QuarterDiscountStrategy.class.getName(),new QuarterDiscountStrategy());        
    }
    public void applyStrategy(OfferStrategy strategy){
        /* 
        Currently applyStrategy has simple implementation. You can use Context for populating some more information,
        which is required to call a particular operation            
        */
        System.out.println("Price before offer :"+price);
        double finalPrice = price - (price*strategy.getDiscountPercentage());
        System.out.println("Price after offer:"+finalPrice);
    }
    public OfferStrategy getStrategy(int monthNo){
        /*
            In absence of this Context method, client has to import relevant concrete Strategies everywhere.
            Context acts as single point of contact for the Client to get relevant Strategy
        */
        if ( monthNo < 6 )  {
            return strategyContext.get(NoDiscountStrategy.class.getName());
        }else{
            return strategyContext.get(QuarterDiscountStrategy.class.getName());
        }

    }
}
public class StrategyDemo{    
    public static void main(String args[]){
        StrategyContext context = new StrategyContext(100);
        System.out.println("Enter month number between 1 and 12");
        int month = Integer.parseInt(args[0]);
        System.out.println("Month ="+month);
        OfferStrategy strategy = context.getStrategy(month);
        context.applyStrategy(strategy);
    }

}

उत्पादन:

Enter month number between 1 and 12
Month =1
Price before offer :100.0
Price after offer:100.0

Enter month number between 1 and 12
Month =7
Price before offer :100.0
Price after offer:75.0

उपयोगी लेख:

dzone द्वारा रणनीति पैटर्न

सोर्सिंग द्वारा रणनीति पैटर्न


12

मैं कई सरल उदाहरणों के बारे में सोच सकता हूं:

  • एक सूची को क्रमबद्ध करना। रणनीति यह निर्धारित करने के लिए उपयोग की जाती है कि सूची में दो में से कौन सी वस्तु "प्रथम" है
  • आपके पास एक ऐसा एप्लिकेशन हो सकता है जहां छंटाई एल्गोरिथ्म खुद (QuickSort, HeapSort, आदि) रनटाइम पर चुना जा सकता है
  • App4, Logouts और Log4Net और Log4j में फिल्टर
  • UI टूलकिट में लेआउट प्रबंधक
  • आधार - सामग्री संकोचन। आपके पास एक ICompressor इंटरफ़ेस हो सकता है जिसका एकमात्र तरीका कुछ इस तरह दिखता है:

    बाइट [] संपीड़ित (बाइट [] इनपुट);

    आपकी कंक्रीट कंप्रेशन क्लासेस RunLengthCompression, DeflateCompression आदि जैसी चीजें हो सकती हैं।


9

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

List<String> names = Arrays.asList("Anne", "Joe", "Harry");
Collections.sort(names, new Comparator<String>() {
  public int compare(String o1, String o2) {
    return o1.length() - o2.length();
  }
});
Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names);

एक समान तरीके से, ऑब्जेक्ट डेटाबेस के साथ मूल प्रश्नों के लिए रणनीतियों का उपयोग किया जा सकता है, उदाहरण के लिए db4o में:

List<Document> set = db.query(new Predicate<Document>() {
  public boolean match(Document candidate) {
    return candidate.getSource().contains(source);
  }
});

8

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

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

मुझे नहीं पता कि यह कितना सामान्य है, लेकिन मुझे ऐसा लगा कि यह रणनीति के पैटर्न के लिए एकदम सही है।


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

7

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

यह दस्तावेज़ वितरण प्रणाली में उपयोग किए जा रहे रणनीति पैटर्न का एक बहुत ही व्यावहारिक उदाहरण है।

मेरे पास एक पीडीएफ डिलीवरी सिस्टम था जिसमें बहुत सारे दस्तावेज और कुछ मेटाडेटा युक्त एक संग्रह प्राप्त हुआ। मेटाडेटा के आधार पर, यह तय किया कि दस्तावेज़ को कहाँ रखा जाए; कहते हैं, डेटा के आधार पर, मैं में दस्तावेज़ संग्रहीत कर सकती है A, Bया Cभंडारण प्रणालियों, या तीनों के मिश्रण।

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

समस्या को हल करने के लिए, मैंने एक बुनियादी डिलीवरी क्लास बनाई है जिसमें डिलीवरी लॉजिक है, साथ ही सभी स्टोरेज से सामान वापस लाने के तरीके। उन तरीकों को त्रुटियों के मामले में सीधे वितरण प्रणाली द्वारा नहीं बुलाया जाता है। इसके बजाय, क्लास "रोलबैक / एरर हैंडलिंग स्ट्रेटेजी" क्लास प्राप्त करने के लिए डिपेंडेंसी इंजेक्शन का उपयोग करता है (सिस्टम का उपयोग करते हुए ग्राहक के आधार पर), जिसे त्रुटियों के मामले में कहा जाता है, जो बदले में रोलबैक विधियों को कॉल करता है यदि यह उस रणनीति के लिए उपयुक्त है।

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

rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);

if (rollbackStrategy.mustAbort()) {
    rollbackStrategy.rollback(); // rollback whatever is needed based on reports
    return false;
}

इसलिए मेरे पास अब दो अलग-अलग रणनीतियाँ हैं: एक वह है QuitterStrategy(जो पहली त्रुटि पर क्विट करता है और कुछ भी साफ नहीं करता है) और दूसरा वह है जो MaximizeDeliveryToAStrategy(जितना संभव हो उतना संभव है कि प्रक्रिया को निरस्त न किया जाए और कभी भी स्टोरेज के लिए रोलबैक सामान वितरित न किया जाए A, लेकिन Bयदि वितरण Cविफल रहता है) से सामान की वापसी ।

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

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

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

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


6

रणनीति का पैटर्न आमतौर पर मान्यताओं और सॉर्टिंग एल्गोरिदम के लिए सबसे अधिक इस्तेमाल किया जाने वाला पैटर्न है।

मुझे एक सरल व्यावहारिक उदाहरण के साथ समझाते हैं

enum Speed {
  SLOW, MEDIUM, FAST;
}

class Sorter {
 public void sort(int[] input, Speed speed) {
    SortStrategy strategy = null;
    switch (speed) {
    case SLOW:
        strategy = new SlowBubbleSortStrategy();
        break;
    case MEDIUM:
        strategy = new MediumInsertationSortStrategy();
        break;

    case FAST:
        strategy = new FastQuickSortStrategy();
        break;
    default:
        strategy = new MediumInsertationSortStrategy();
    }
    strategy.sort(input);
 }

}

interface SortStrategy {

    public void sort(int[] input);
}

class SlowBubbleSortStrategy implements SortStrategy {

   public void sort(int[] input) {
    for (int i = 0; i < input.length; i++) {
        for (int j = i + 1; j < input.length; j++) {
            if (input[i] > input[j]) {
                int tmp = input[i];
                input[i] = input[j];
                input[j] = tmp;
            }
        }
    }
    System.out.println("Slow sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
  }

 }

class MediumInsertationSortStrategy implements SortStrategy {

public void sort(int[] input) {
    for (int i = 0; i < input.length - 1; i++) {
        int k = i + 1;
        int nxtVal = input[k];
        while (input[k - 1] > nxtVal) {
            input[k] = input[k - 1];
            k--;
            if (k == 0)
                break;
        }
        input[k] = nxtVal;
    }
    System.out.println("Medium sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }

 }

}

class FastQuickSortStrategy implements SortStrategy {

public void sort(int[] input) {
    sort(input, 0, input.length-1);
    System.out.println("Fast sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
}

private void sort(int[] input, int startIndx, int endIndx) {
    int endIndexOrig = endIndx;
    int startIndexOrig = startIndx;
    if( startIndx >= endIndx)
        return;
    int pavitVal = input[endIndx];
    while (startIndx <= endIndx) {
        while (input[startIndx] < pavitVal)
            startIndx++;
        while (input[endIndx] > pavitVal)
            endIndx--;
        if( startIndx <= endIndx){
            int tmp = input[startIndx];
            input[startIndx] = input[endIndx];
            input[endIndx] = tmp;
            startIndx++;
            endIndx--;
        }
    }
    sort(input, startIndexOrig, endIndx);
    sort(input, startIndx, endIndexOrig);
 }

}  

इसके लिए टेस्ट कोड है

public class StrategyPattern {
  public static void main(String[] args) {
    Sorter sorter = new Sorter();
    int[] input = new int[] {7,1,23,22,22,11,0,21,1,2,334,45,6,11,2};
    System.out.print("Input is : ");
    for (int i : input) {
        System.out.print(i + ",");
    }
    System.out.println();
    sorter.sort(input, Speed.SLOW);
 }

}

एक ही उदाहरण http://coder2design.com/strategy-pattern/ से लिया गया है


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

5

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


1
मैंने सोचा था कि स्वीकृत उत्तर इस उदाहरण के बारे में बात करने वाला था :)
जीनकरलो फानाल्वो

2

मैंने एक एप्लिकेशन में एक काफी जटिल इंजन में रणनीति दृष्टिकोण का उपयोग किया जो एक अच्छा उदाहरण है। अनिवार्य रूप से इंजन की भूमिका को जाने और पहले उन लोगों की एक सूची ढूंढना था जिनके पास विजेट था, यह दूसरी भूमिका है यह पता लगाने के लिए कि 10 सर्वश्रेष्ठ लोग कौन से थे जो एक अज्ञात संख्या के मापदंडों पर आधारित थे (चीजें जैसे मूल्य दूरी पिछले व्यापार एक साथ , स्टॉक पर अमाउंट, शिपिंग विकल्प आदि आदि ...)

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

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

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

यदि हम एक रणनीति या एक टेम्पलेट पैटर्न का उपयोग कर रहे थे तो हमने कुछ बहसें कीं जो हमने कभी हल नहीं कीं।


2

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

उदाहरण के लिए विधि पर ऑर्डर के लिए जहाज लें :

order.Ship();
  • यदि शिपिंग विधि इसकी स्थिति के कार्य में भिन्न है, तो आपको एक रणनीति पैटर्न मिल गया है।
  • यदि फिर भी शिप () विधि केवल तभी सफल होती है जब ऑर्डर का भुगतान किया गया हो, और ऑर्डर अभी तक शिप नहीं किया गया है, तो आपको एक स्टेट पैटर्न मिल गया है।

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


2

मान लें कि आप किसी दिए गए महीने और वर्ष की nth Xday की गणना करने के लिए एक एल्गोरिथम लिखना चाहते हैं , उदाहरण के लिए, अक्टूबर 2014 का दूसरा सोमवार। आप android.text.format.Timeतारीख का प्रतिनिधित्व करने के लिए एंड्रॉइड के टाइम क्लास का उपयोग करना चाहते हैं , लेकिन आप एक सामान्य एल्गोरिथ्म भी लिखना चाहते हैं। उस पर भी लागू हो सकता है java.util.Calendar

यह जो मैंने किया है।

DatetimeMath.java में:

public interface DatetimeMath { 
    public Object createDatetime(int year, int month, int day);

    public int getDayOfWeek(Object datetime);

    public void increment(Object datetime);
}

TimeMath.java में:

public class TimeMath implements DatetimeMath {
    @Override
    public Object createDatetime(int year, int month, int day) {
        Time t = new Time();
        t.set(day, month, year);
        t.normalize(false);
        return t;
    }

    @Override
    public int getDayOfWeek(Object o) {
        Time t = (Time)o;
        return t.weekDay;
    }   

    @Override
    public void increment(Object o) {
        Time t = (Time)o;
        t.set(t.monthDay + 1, t.month, t.year);
        t.normalize(false);
    }
}

ऑर्डिनलडेऑफ़वेकलकुलर.जावा में, सामान्य एल्गोरिथ्म के साथ वर्ग:

public class OrdinalDayOfWeekCalculator {   
    private DatetimeMath datetimeMath;

    public OrdinalDayOfWeekCalculator(DatetimeMath m) {
        datetimeMath = m;
    }

    public Object getDate(int year, int month, int dayOfWeek, int ordinal) {
        Object datetime = datetimeMath.createDatetime(year, month, 1);
        if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
            return datetime;
        } 
        int xDayCount = 0;
        while (xDayCount != ordinal) {
            datetimeMath.increment(datetime);
            if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
                xDayCount++;
            }
        }
        return datetime;
    }
}

अपने एंड्रॉइड ऐप में, मैं कुछ ऐसा कहूंगा

OrdinalDayOfWeekCalculator odowc = 
        new OrdinalDayOfWeekCalculator(new TimeMath());
Time canadianThanksgiving = (Time)odowc.getDate(
        year, Calendar.OCTOBER, Time.MONDAY, 2);

अगर मैं उसी एल्गोरिथ्म का पुन: उपयोग करना चाहता हूं java.util.Calendar, तो मैं सिर्फ एक क्लास कैलेंडरमैथ लिखूंगा जो डेटाटाइममैथ में तीन तरीकों को लागू करता है और फिर उपयोग करता है

OrdinalDayOfWeekCalculator odowc2 = 
        new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
        year, Calendar.OCTOBER, Calendar.MONDAY, 2);

2
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        Item item1 = new Item("1234", 10);
        Item item2 = new Item("5678", 40);

        cart.addItem(item1);
        cart.addItem(item2);

        // pay by paypal
        cart.pay(new PaypalStrategy("myemail@example.com", "mypwd"));

        // pay by credit card
        cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
    }
}

interface PaymentStrategy {
    public void pay(int amount);
}

class CreditCardStrategy implements PaymentStrategy {

    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
        this.name = nm;
        this.cardNumber = ccNum;
        this.cvv = cvv;
        this.dateOfExpiry = expiryDate;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid with credit/debit card");
    }

}

class PaypalStrategy implements PaymentStrategy {

    private String emailId;
    private String password;

    public PaypalStrategy(String email, String pwd) {
        this.emailId = email;
        this.password = pwd;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using Paypal.");
    }

}

class Item {

    private String upcCode;
    private int price;

    public Item(String upc, int cost) {
        this.upcCode = upc;
        this.price = cost;
    }

    public String getUpcCode() {
        return upcCode;
    }

    public int getPrice() {
        return price;
    }

}

class ShoppingCart {

    // List of items
    List<Item> items;

    public ShoppingCart() {
        this.items = new ArrayList<Item>();
    }

    public void addItem(Item item) {
        this.items.add(item);
    }

    public void removeItem(Item item) {
        this.items.remove(item);
    }

    public int calculateTotal() {
        int sum = 0;
        for (Item item : items) {
            sum += item.getPrice();
        }
        return sum;
    }

    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}

1

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

public interface CollectibleElephant { 
    long getId();
    String getName();
    long getTagId();
}

public class Elephant implements CollectibleElephant { ... }
public class BabyElephant implements CollectibleElephant { ... }

मूल रूप से, मैं CollectibleElephantसॉर्ट करने के लिए उपयोग करना चाहता था Elephant। बहुत जल्दी, मेरे साथियों ने CollectibleElephantसुरक्षा जांच चलाने के लिए, उन्हें फ़िल्टर करना शुरू कर दिया, क्योंकि वे जीयूआई को भेजते हैं, आदि।


1

हमें एक बहुत ही जटिल डेटाबेस के साथ एक एंटरप्राइज़ प्लेटफ़ॉर्म के लिए एक तृतीय-पक्ष प्रावधान इंटरफ़ेस बनाना था। प्रावधान किए जाने वाले डेटा को प्रस्तुत करना हमारे डेटा प्रकारों की एक सूची के रूप में था जो हमारे आवेदन में एक प्राथमिकता कतार में रखा गया था ताकि वे निर्भरता के कारण सही क्रम में डेटाबेस को लिखा जा सके।

उस डेटा को लिखने की प्रक्रिया तब काफी सरल थी, प्राथमिकता कतार के शीर्ष पर पॉपिंग रखें और फिर उस ऑब्जेक्ट के प्रकार के आधार पर एक रणनीति चुनें जिसे आप निकालते हैं।


0

विकिपीडिया से

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

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

यदि आप 'RedCircle' का विकल्प प्रदान करने के बजाय लाल रंग के साथ एक वृत्त खींचना चाहते हैं, तो वे आपको चक्र और अपनी पसंद का रंग चुनने देते हैं।

Shape redCircle = new RedCircle(); // Without stretegy Pattern
Shaped redCircle = new Shape("red","circle"); // With Strategy pattern

बिना रणनीति पैटर्न के आकार और रंग के कार्टेशियन उत्पाद के साथ कक्षाओं की संख्या में वृद्धि होगी। प्रत्येक कार्यान्वयन के लिए इंटरफ़ेस भी बदलता है।


0

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

interface FightingStategy{
    public void fight();
}
public Defense implements FightingStrategy{
    public void figth(){
        ... hide behind wall to shoot
    }
}
public Berserker implements FightingStrategy{
    public void fight(){
        ... run towards you, headrolls and shoots
    }
}
public Dead implements FightingStrategy{
    public void fight(){
        ... is dead, doesn't move
    }
}

public AiShooter{

    FightingStrategy fightingStrategy;

    public AiShooter(){
        fightStrategy = new Berserker();
    }

    public void fight(){
        this.fightingStrategy.fight();
    }

    public void changeStrategy(FightingStrategy f){
        this.fightingStrategy = f;
    }
}

public static void main(){

    ... create list of AiShooters...
    while (condition){
        list.forEach(shooter -> shooter.fight());
    }
    ... you shoot back
    list.ForEach(shooter -> shooter.changeStrategy(new 
Defense()));

    ... you kill one
    list.get(n).changeStrategy(new Dead());
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.