2012-11-01 9 views
7

को पुन: सक्रिय करने में सहायता मेरे पास सी पृष्ठभूमि है और सी ++ पर एक नया है। मेरे पास एक बुनियादी डिजाइन सवाल है। मैं एक वर्ग (मैं इसे "महाराज" ख/ग समस्या मैं यह करने के लिए बहुत अनुरूप लगता है फोन करता हूँ, दोनों जटिलता और मुद्दों के संदर्भ में) कि मूल रूप से इससी ++ राक्षस वर्ग

class chef 
    { 
    public: 
      void prep(); 
      void cook(); 
      void plate(); 

    private: 
      char name; 
      char dish_responsible_for; 
      int shift_working; 
      etc... 
    } 
छद्म कोड में

की तरह काम करता है, इस की तर्ज पर लागू किया जाता है:

int main{ 
    chef my_chef; 
    kitchen_class kitchen; 
    for (day=0; day < 365; day++) 
     { 
     kitchen.opens(); 
     .... 

     my_chef.prep(); 
     my_chef.cook(); 
     my_chef.plate(); 

     .... 

     kitchen.closes(); 
     } 
    } 

महाराज वर्ग यहाँ एक राक्षस वर्ग हो रहा है, और एक बनने की क्षमता है। महाराज भी एक जिम्मेदारी सिद्धांत का उल्लंघन करने लगता है, इसलिए बजाय हम की तरह कुछ होना चाहिए:

class employee 
    { 
    protected: 
     char name; 
     int shift_working; 
    } 

    class kitchen_worker : employee 
    { 
    protected: 
     dish_responsible_for; 
    } 

    class cook_food : kitchen_worker 
    { 
    public: 
     void cook(); 
     etc... 
    } 
    class prep_food : kitchen_worker 
    { 
    public: 
     void prep(); 
     etc... 
    } 

और

 class plater : kitchen_worker 
    { 
    public: 
     void plate(); 
    } 

आदि ...

मैं वैसे अभी भी साथ कैसे के लिए संघर्ष कर रहा हूँ इसे रन टाइम पर कार्यान्वित करें ताकि, उदाहरण के लिए प्लाटर (या "प्लेटर के रूप में अपनी क्षमता में शेफ") रात्रिभोज सेवा के माध्यम से घर के माध्यम से जाने का फैसला करता है, तो शेफ को एक नई शिफ्ट करना पड़ता है।

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

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

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

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

+0

कभी कभी असली दुनिया भूमिकाओं/जिम्मेदारियों/कोड में वस्तुओं के लिए कार्य मानचित्रण सिर्फ काम नहीं करता। शायद आपको कुछ सामान्य कार्य की आवश्यकता है जो एक व्यक्ति और एक कार्रवाई लेता है। वह कार्य व्यक्ति को कार्रवाई लागू करने के लिए मिलता है। –

+0

प्रत्येक वर्ग इंटरफ़ेस पर मॉड्यूल आपको अधिक सुराग दे सकता है? एक प्लेटर क्या कर सकता है? क्या cook_food कर सकते हैं? क्या उन्हें विरासत में रहने की आवश्यकता है या यह सिर्फ एक कौशल (फ़ंक्शन कॉल) है? – billz

+0

संरचना विधि को देखो। या शायद आपको यहां एक राज्य पैटर्न की आवश्यकता है? –

उत्तर

3

अब और भविष्य में वर्ग heirarchies कोस बचने के लिए आप वास्तव में केवल यह प्रयोग करना चाहिए जब एक संबंध मौजूद है।अपने आप के रूप में, "cook_food एक kitchen_worker है"। यह स्पष्ट रूप से वास्तविक जीवन में समझ में नहीं आता है, और कोड में भी नहीं है। "cook_food" एक क्रिया है, इसलिए इसके बजाय एक एक्शन क्लास बनाने और उपclass बनाने के लिए यह समझ में आ सकता है।

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

class action { 
    public: 
     virtual void perform_action()=0; 
} 

class cook_food : public action { 
    public: 
     virtual void perform_action() { 
      //do cooking; 
     } 
} 

एक शेफ को आपके द्वारा निर्दिष्ट क्रम में निष्पादित करने के लिए कार्यों की एक सूची दी जा सकती है। उदाहरण के लिए कहें, एक कतार।

class chef { 
    ... 
     perform_actions(queue<action>& actions) { 
      for (action &a : actions) { 
       a.perform_action(); 
      } 
     } 
    ... 
} 

यह और अधिक सामान्यतः Strategy Pattern के रूप में जाना जाता है। यह आपके मौजूदा वर्गों को संशोधित किए बिना नए कार्यों को जोड़ने की अनुमति देकर खुले/बंद सिद्धांत को बढ़ावा देता है।


एक वैकल्पिक दृष्टिकोण आप इस्तेमाल कर सकते हैं एक Template Method है, जहां आप सार चरणों का क्रम निर्दिष्ट करें, और हर एक के लिए विशिष्ट व्यवहार को लागू करने के उपवर्गों का उपयोग करें।

class dish_maker { 
    protected: 
     virtual void prep() = 0; 
     virtual void cook() = 0; 
     virtual void plate() = 0; 

    public: 
     void make_dish() { 
      prep(); 
      cook(); 
      plate(); 
     } 
} 

class onion_soup_dish_maker : public dish_maker { 
    protected: 
     virtual void prep() { ... } 
     virtual void cook() { ... } 
     virtual void plate() { ... } 
} 

एक और निकट से संबंधित पैटर्न जो इस के लिए उपयुक्त हो सकता है Builder Pattern

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


onion_cutter और carrot_cutter के लिए अलग अलग वर्गों बनाने पर, यह वास्तव में SRP का तार्किक निष्कर्ष नहीं है, लेकिन वास्तव में यह का उल्लंघन - क्योंकि तुम वर्ग है जो काटने के लिए जिम्मेदार हैं कर रहे हैं, और पकड़े वे क्या कटौती कर रहे हैं के बारे में कुछ जानकारी। प्याज और गाजर काटने दोनों को एक काटने की क्रिया में वर्गीकृत किया जा सकता है - और आप निर्दिष्ट कर सकते हैं कि कौन सा ऑब्जेक्ट काटने के लिए, और प्रत्येक ऑब्जेक्ट के लिए विशिष्ट कोड की आवश्यकता होने पर प्रत्येक व्यक्तिगत वर्ग में एक पुनर्निर्देशन जोड़ें।

कुछ कदम कहने के लिए एक अमूर्तता बनाना एक कदम होगा। सबक्लासिंग के लिए संबंध उम्मीदवार है, क्योंकि गाजर कटटेबल है।

class cuttable { 
    public: 
     virtual void cut()=0; 
} 

class carrot : public cuttable { 
    public: 
     virtual void cut() { 
      //specific code for cutting a carrot; 
     } 
} 

काटने कार्रवाई एक cuttable वस्तु ले जा सकते हैं और किसी भी आम काटने कार्रवाई है कि सभी cuttables प्रकार लागू होता है करते हैं, और भी प्रत्येक वस्तु के विशिष्ट कटौती व्यवहार लागू कर सकते हैं।

class cutting_action : public action { 
    private: 
     cuttable* object; 
    public: 
     cutting_action(cuttable* obj) : object(obj) { } 
     virtual void perform_action() { 
      //common cutting code 
      object->cut(); //specific cutting code 
     } 
} 

+0

इसके लिए धन्यवाद। मेरा मतलब है कि इसे एक प्रश्न के साथ पालन करना है। इसलिए यदि हम रणनीति पैटर्न दृष्टिकोण का पालन करते हैं, तो कहें कि प्रत्येक शेफ में कई डेटा सदस्य होते हैं (उदाहरण के लिए, tasting_spoon, salt_shaker, आदि ...) cook_food() और plate_dish() वर्ग दोनों में उपयोग किया जाता है। ऐसा लगता है कि क्लास शेफ को cook_food() और cook_food() को क्लास शेफ की आवश्यकता होती है। Cook_food() वर्ग में तर्कों का एक टन देने के बिना cook_food() और क्लास शेफ कहने के बीच सर्कुलर निर्भरता से कैसे बचता है? एक डिजाइन परिप्रेक्ष्य से, यदि कक्षाएं अत्यधिक युग्मित हैं, तो क्या उन्हें अलग करने के लिए कोई कमी नहीं है? – user1790399

+0

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

+0

क्षमा करें, कक्षा के लिए इंटरफ़ेस का उपभोग करने में सक्षम होने का क्या अर्थ है? क्या इसका मतलब कुछ ऐसा करना है, अगर हम शेफ क्लास पर इंटरफ़ेस के साथ जाते हैं, उदाहरण के लिए, cook_food (chef-> interface_for_cooking()), इंटरफ़ेस_for_cooking() के साथ get_salt_shaker(), get_tasting_spoon() आदि जैसे कॉल से बना है .. ।? और इस उदाहरण के साथ पालन करने के लिए, cook_food() और plate_dish() कक्षाओं के लिए दो अलग-अलग इंटरफेस रखना एक बुरा विचार होगा? – user1790399

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