2015-03-13 16 views
5

मैं सी ++ में रणनीति पैटर्न को लागू करने का सबसे अच्छा तरीका बता रहा हूं।सीडी + में रणनीति पैटर्न को कैसे लागू करें std :: function

class AbstractStrategy{ 
public: 
    virtual void exec() = 0; 
} 
class ConcreteStrategyA{ 
public: 
    void exec(); 
} 
class ConcreteStrategyB{ 
public: 
    void exec(); 
} 

class Context{ 
public: 
    Context(AbstractStrategy* strategy):strategy_(strategy){} 
    ~Context(){ 
      delete strategy; 
     } 
     void run(){ 
      strategy->exec(); 
     } 
private: 
    AbstractStrategy* strategy_; 

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

क्या कोई व्यक्ति बेहतर तरीके से समझा सकता है कि std::function काम करता है, शायद रणनीति पैटर्न के साथ एक उदाहरण के साथ?

उत्तर

7

ध्यान दें कि सिंगल-विधि ऑब्जेक्ट्स कार्य करने के लिए आइसोमोर्फिक हैं, और रणनीतियों केवल एकल-विधि वस्तुएं हैं।

तो मूल रूप से, आप अपने सभी वर्गों से छुटकारा पाने के लिए, और तुम सिर्फ std::function<void()> बजाय का उपयोग करें:

Context ctx([] { std::cout << "Hello, world!\n"; }); 
ctx.run(); 
+0

इस मामले में, आप एफ (रणनीति) को कैसे कार्यान्वित करेंगे? और आपको std :: move का उपयोग करने की आवश्यकता क्यों है? – gcswoosh

+2

@ गैब्रिलेक्सवोश रणनीति केवल ऑपरेटर() 'ओवरलोडेड के साथ कोई फ़ंक्शन पॉइंटर या ऑब्जेक्ट है।मेरा उदाहरण एक लैम्ब्डा पास करता है (जो 'शून्य ऑपरेटर()() const' को परिभाषित करता है)। 'std :: move' एक प्रति को रोकने के लिए है। – rightfold

0

कुछ की तरह:

class Context { 
public: 
    template<typename F> 
    explicit Context(F strategy) : strategy(std::move(strategy)) { } 

    void run() { strategy(); } 

private: 
    std::function<void()> strategy; 
}; 

तो फिर तुम Context के निर्माता के लिए किसी भी प्रतिदेय पारित कर सकते हैं इस ?

#include <functional> 
#include <iostream> 


typedef std::function<int(int)> Strategy; 

void execute_strategy(Strategy strategy, int object) { 
    std::cout << strategy(object) << std::endl; 
}; 

int power2(int i) { 
    return i*i; 
}; 

int main() { 
    execute_strategy(power2, 3); 
} 

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

3

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

+0

इस मामले में आप क्या सुझाव देंगे जहां रणनीति एक फंक्शन कॉल आसान नहीं है? उस मामले में एक अमूर्त वर्ग के लिए एक सूचक एकमात्र तरीका है? – gcswoosh

+1

हां। आप उचित संसाधन नियंत्रण को 'std :: unique_ptr' या' std :: shared_ptr' के साथ उचित रूप से संभाल सकते हैं। – sfjac

1

райтфолд

मूल रूप से, आप अपने सभी वर्गों से छुटकारा पाने के जवाब पर काम करते हुए, और तुम सिर्फ बजाय std :: समारोह का उपयोग करें।

Context ctx([] { std::cout << "Hello, world!\n"; }); 
ctx.run(); 
:

यह सामान्यीकृत समारोह आप काम करता है, लैम्ब्डा, functors, और सदस्य कार्य (std :: बाँध का प्रयोग करके) पारित करने के लिए

class Context { 
public: 
    explicit Context(std::function<void()> input) : strategy(input) { } 

void run() { strategy(); } 

private: 
    std::function<void()> strategy; 
}; 

तो फिर तुम प्रसंग के निर्माता के लिए किसी भी प्रतिदेय पारित कर सकते हैं अनुमति देता है

या

void sayHelloWorld(){ 
    std::cout << "Hello, world!\n"; 
} 


int main(){ 
    Context ctx(sayHelloWorld); 
    ctx.run(); 
} 

या
class SayHelloWorld{ 
    operator()(){std::cout << "Hello, world!\n";} 
} 

int main(){ 
    SayHelloWorld hello_world; 
    Context ctx(hello_world); 
    ctx.run(); 
} 
संबंधित मुद्दे