2012-04-04 12 views
5

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

निम्नलिखित उदाहरण लें (यह है कि राज्य का प्रतिनिधित्व करने के लिए एक गणना का उपयोग करता है):

public class Vacancy { 

    private VacancyState currentState; 

    public void Approve() { 
     if (CanBeApproved()) { 
      currentState.Approve(); 
     } 
    } 

    public bool CanBeApproved() { 
     return currentState == VacancyState.Unapproved 
      || currentState == VacancyState.Removed 
    } 

    private enum VacancyState { 
     Unapproved, 
     Approved, 
     Rejected, 
     Completed, 
     Removed 
    } 
} 

आप देख सकते हैं कि इस वर्ग के ही हम अस्वीकार करने के लिए तरीके, पूरा जोड़ने के रूप में काफी वर्बोज़ बन जाएगा, निकालें आदि

public abstract class VacancyState { 

    protected Vacancy vacancy; 

    public VacancyState(Vacancy vacancy) { 
     this.vacancy = vacancy; 
    } 

    public abstract void Approve(); 
    // public abstract void Unapprove(); 
    // public abstract void Reject(); 
    // etc. 

    public virtual bool CanApprove() { 
     return false; 
    } 
} 

public abstract class UnapprovedState : VacancyState { 

    public UnapprovedState(vacancy) : base(vacancy) { } 

    public override void Approve() { 
     vacancy.State = new ApprovedState(vacancy); 
    } 

    public override bool CanApprove() { 
     return true; 
    } 
} 

इससे betwee संक्रमण के लिए बनाता है:

इसके बजाय हम राज्य पैटर्न है, जो हमें एक वस्तु के रूप में प्रत्येक राज्य को संपुटित करने की अनुमति देता लागू कर सकते हैं n राज्यों, वर्तमान स्थिति के आधार तर्क करते हैं या नए राज्यों को जोड़ने अगर हम की जरूरत है:

// transition state 
vacancy.State.Approve(); 

// conditional 
model.ShowRejectButton = vacancy.State.CanReject(); 

यह कैप्सूलीकरण क्लीनर लगता है, लेकिन पर्याप्त राज्यों को देखते हुए इन भी बहुत वर्बोज़ बन सकता है। मैंने Greg Young's post on State Pattern Misuse पढ़ा है जो इसके बजाय बहुरूपता का उपयोग करने का सुझाव देता है (इसलिए मुझे स्वीकृत वैकेंसी, अपरिवर्तनीयता आदि कक्षाएं होंगी), लेकिन यह नहीं देख सकता कि यह मेरी मदद कैसे करेगा।

क्या मुझे डोमेन सेवा में ऐसे राज्य संक्रमणों का प्रतिनिधि होना चाहिए या इस स्थिति में राज्य पैटर्न का मेरा उपयोग सही है?

उत्तर

5

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

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

यह मुझे राज्य पैटर्न के उपयोग के लिए प्रेरित करता है। अधिकांश भाग के लिए, आप पैटर्न का सही ढंग से उपयोग कर रहे हैं। एक हिस्सा जहां आप थोड़ा सा भटकते हैं, आपके डेमेटर उल्लंघन के कानून में है। आपके ऑब्जेक्ट का उपभोक्ता आपके ऑब्जेक्ट में नहीं पहुंच सकता है और इसके राज्य पर कॉल विधियों तक नहीं पहुंच सकता है (उदाहरण के लिए रिक्ति.स्टेट। कैनरेजेक्ट()), बल्कि आपकी ऑब्जेक्ट को इस ऑब्जेक्ट को स्टेट ऑब्जेक्ट (जैसे रिक्ति.कैनरेजेक्ट() - > बूल CanReject() {वापसी _state.CanReject();})। आपके ऑब्जेक्ट के उपभोक्ता को यह नहीं पता होना चाहिए कि आप राज्य पैटर्न का भी उपयोग कर रहे हैं।

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

+0

यदि उपभोक्ता को सीधे राज्य को नहीं बदलना चाहिए तो इसका मतलब है कि मैं अपनी इकाई पर प्रत्येक राज्य संक्रमण के लिए एक विधि के साथ समाप्त हो जाऊंगा। तो मैं वास्तव में यहाँ क्या प्राप्त कर रहा हूँ? –

+2

यदि आप बयानों के समूह के encapsulation और अनुपस्थिति प्राप्त करते हैं :) यहां आधिकारिक लाभ हैं: 1. यह अलग-अलग राज्यों के लिए राज्य-विशिष्ट व्यवहार और विभाजन व्यवहार को स्थानीयकृत करता है। 2. यह राज्य संक्रमण स्पष्ट करता है। 3. राज्य वस्तुओं को साझा किया जा सकता है। –

+0

धन्यवाद।एक अंतिम सवाल - हम रिक्ति को एक दस्तावेज़ स्टोर (रावेनडीबी) में बना रहे हैं। क्या आप एक ऐसे एनम को जारी रखने का सुझाव देते हैं जिसका उपयोग प्रासंगिक राज्य ऑब्जेक्ट को लोड करने के लिए किया जाता है या सिर्फ पूरे राज्य ऑब्जेक्ट को संग्रहीत करता है –