2009-04-08 17 views
9

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

यहाँ मैं क्या सोच रहा था:

public interface ITax 
{ 
    decimal ProvincialTaxRate { get; set; } // Yes, I'm Canadian :) 
    decimal CalculateTax(decimal subtotal); 
} 

public SaskatchewanTax 
{ 
    public decimal ProvincialTaxRate { get; set; } 

    public SaskatchewanTax() 
    { 
     ProvincialTaxRate = new decimal(0.05f); 
    } 

    public decimal CalculateTax(subtotal) 
    { 
     return ProvincialTaxRate * subtotal + FederalTaxRate * subtotal; 
    } 
} 

public OntarioTax 
{ 
    public decimal ProvincialTaxRate { get; set; } 

    public OntarioTax() 
    { 
     ProvincialTaxRate = new decimal(0.08f); 
    } 

    public decimal CalculateTax(decimal subtotal) 
    { 
     return ProvincialTaxRate * subtotal + FederalTaxRate * subtotal; 
    } 
} 

आपने ध्यान दिया होगा FederalTaxRate का कोई घोषणा नहीं है और वह है क्या मैं पूछने के लिए चाहता था। उसे कहाँ जाना चाहिए?

  • प्रत्येक ठोस आईटीएक्स के लिए इसे कन्स्ट्रक्टर में पास करना अनावश्यक लगता है और गलत व्यवहार की अनुमति देगा (सभी कर कैलकुलेटर को समान संघीय कर दर को साझा करना होगा)।
  • इसी तरह, आईटीएक्स के सदस्य को बनाने से उन्हें असंगत होने की अनुमति मिल जाएगी।

क्या सभी टैक्स कैलकुलेटर किसी अन्य वर्ग से प्राप्त होते हैं जहां इसे स्थिर रूप से और आईटीएक्स परिभाषित किया जाता है? एक आधार वर्ग कि कनाडा की संघीय फैक्स जिस दर से अपने व्युत्पन्न वर्ग के सभी वारिस कर सकते हैं बना सकते हैं -

public class TaxCalculator 
{ 
    public static decimal FederalTaxRate = new decimal(0.05f); 
} 

उत्तर

21

मुझे लगता है कि यह पैटर्न दुरुपयोग का एक आम मामला है।

यदि आप अपनी दो "रणनीतियों" की जांच करते हैं, तो वे बिल्कुल वही काम करते हैं। एकमात्र चीज जो बदलती है वह प्रांतीय टैक्सराट है।

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

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

मेरे राय: रख इसे सरल

सादर

संपादित

मैं तुम्हें मजाक बनाने, या किसी को भी करने की कोशिश नहीं (मेरे जवाब पर लेखक टिप्पणी के जवाब में)। यह एक आम गलती है, मैंने इसे कई बार किया, और न केवल पैटर्न के साथ बल्कि फैंसी फ्रेमवर्क, सर्वर, नई buzzword प्रौद्योगिकियों के साथ, आप इसे नाम भी कठिन तरीका सीखा।

पुस्तक के लेखकों ने खुद को पाठकों को चेतावनी दी है कि वे पैटर्न का उपयोग न करें, और इस उत्तर में उपरोक्त स्पष्ट रूप से कुछ भी इंगित करते हैं।

लेकिन अगर आप अभी पैटर्न लागू करना चाहते हैं किसी कारण से, यहाँ मेरी विनम्र राय है:

  • दोनों रणनीतियों के लिए एक सुपर क्लास बनाने, इस सुपर क्लास सार होगा और साझा दर मूल्य को शामिल करना चाहिए उनके बच्चे रणनीतियों (FederalTaxRate)

  • इनहेरिट और प्रत्येक उपवर्ग में सार विधि "गणना" को लागू (यहाँ आपको लगता है कि दोनों तरीकों ही कर रहे हैं देखेंगे, लेकिन आइए आगे बढ़ें)

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

  • अन्त में, मैं StrategySuperclass में कुछ स्थिर कारखाने तरीके (जो कर सकते हैं अब बहुत अच्छी तरह से संरक्षित किया जाना वर्ग) बना सकते हैं, ताकि आप कार्यान्वयन या ठोस रणनीतियों से अपने ग्राहकों को दसगुणा

संपादित द्वितीय : यहाँ कुछ (छद्म) कोड के साथ एक pastie समाधान में थोड़ा और अधिक स्पष्ट करना है

http://pastie.org/441068

आशा है कि यह मदद करता है

सादर

+0

यह सच हो सकता है, लेकिन यह अभी भी प्रश्न का उत्तर नहीं देता है या मेरे 'मजेदार' बनाने के अलावा मुझे कोई भी उपयोग प्रदान नहीं करता है। –

+0

इस टिप्पणी का जवाब देने के लिए संपादित किया गया^ –

+0

चूंकि ऐसा लगता है कि आप इन पैटर्न को सीख रहे हैं, आपको व्यक्तिगत हमले के रूप में किसी की आलोचना नहीं लेनी चाहिए। आप पहले इन नए पैटर्न का उपयोग करने के हर अवसर की तलाश करेंगे, और कभी-कभी आप उनका दुरुपयोग करेंगे क्योंकि इस प्रतिक्रिया का उल्लेख है। सीखने की प्रक्रिया का सभी हिस्सा। –

2

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

मुझे नहीं लगता कि यह अद्वितीय रूप से सबसे अच्छा समाधान है, लेकिन यह पूरी तरह से अच्छी तरह से काम करेगा। डिजाइन पैटर्न आपके सामान्य ज्ञान के रास्ते में नहीं आना चाहिए, और मुझे लगता है कि सामान्य ज्ञान इस समस्या को ठीक करेगा।

1

कुछ अंक:

  1. ProvincialTaxRate लगभग निश्चित रूप से इंटरफेस स्तर (कोई set संपत्ति) पर अडिग रहना चाहिए। चारों ओर कर दरें बदलना एक अच्छा विचार नहीं लगता है, हालांकि इसका मतलब है कि आप अपने कार्यान्वयन में ऑटो-प्रॉपर्टी का उपयोग नहीं कर सकते हैं।

  2. यदि केवल एक FederalTaxRate है और यह केवल एक साधारण संख्यात्मक मान है, तो मुझे लगता है कि सार आधार वर्ग एक सुरक्षित दृष्टिकोण है।

  3. कम उचित: कैसे करों काम के आधार पर आप तर्क दे सकते हैं कि CalculateTaxFederalTaxRate पर निर्भर करता है और इसलिए इस एक पैरामीटर के रूप आपूर्ति किए जाने की जरूरत है (शायद वहाँ विभिन्न FederalTaxRates रहे हैं और आप CalculateTax नहीं करना चाहती के बारे में पता करने के लिए उन्हें)।

किसी डिज़ाइन पैटर्न की परिभाषा को एक अच्छे विचार के तरीके में न आने दें। वे पैटर्न हैं, सूत्र नहीं। ;)


पीएस मैं एक अमेरिकी हूं, इसलिए यदि कनाडाई कर वास्तव में सरल हैं, तो मुझे उम्मीद है कि आईआरएस अगले वर्ष आपकी पुस्तक से एक पेज लेगा!

2

आप इस कोड के साथ शुरू करते हैं, और वहाँ से आगे बढ़ने के लिए चाहते हो सकता है:

public interface ITax 
{ 
    decimal CalculateTax(decimal subtotal); 
} 

public class SaskatchewanTax : ITax 
{ 
    private readonly decimal provincialTaxRate; 
    private readonly decimal federalTaxRate; 

    public SaskatchewanTax(decimal federalTaxRate) 
    { 
     provincialTaxRate = 0.05m; 
     this.federalTaxRate = federalTaxRate; 
    } 

    public decimal CalculateTax(decimal subtotal) 
    { 
     return provincialTaxRate * subtotal + federalTaxRate * subtotal; 
    } 
} 

public class OntarioTax : ITax 
{ 
    private readonly decimal provincialTaxRate; 
    private readonly decimal federalTaxRate; 

    public OntarioTax(decimal federalTaxRate) 
    { 
     provincialTaxRate = 0.08m; 
     this.federalTaxRate = federalTaxRate; 
    } 

    public decimal CalculateTax(decimal subtotal) 
    { 
     return provincialTaxRate * subtotal + federalTaxRate * subtotal; 
    } 
} 

इस बिंदु पर वहाँ ज्यादा बात दो अलग-अलग रणनीति वस्तुओं कर गणना का प्रतिनिधित्व करने के लिए नहीं हो सकता है, लेकिन एक और अधिक के साथ यथार्थवादी कार्यान्वयन (मुझे लगता है कि कर गणना अधिक जटिल है और प्रांत द्वारा अधिक भिन्न होती है), यह समझ में आ सकती है।

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

+0

मेरे पास कुछ समय के लिए "सबसे आसान चीज जो संभवतः काम कर सकती है" लागू की गई है, लेकिन जैसा कि मैं कोडबेज को और अधिक जोड़ता हूं, मुझे लगता है कि मुझे इस ऑब्जेक्ट को कई ऑब्जेक्ट्स में दोहराना है और दोहराए गए कोड पर वापस कटौती के विभिन्न तरीकों को देख रहा था। –

+0

आप उपरोक्त में कर गणना के लिए (सार) आधार वर्ग में दोहराए गए कोड, और विशिष्ट कार्यान्वयन (रणनीतियों) को डालने पर विचार कर सकते हैं। –

2

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

public abstract class Tax 
{ 
    protected decimal ProvincialTaxRate; // Yes, you are Canadian ;) 
    public decimal CalculateTax(decimal subtotal) 
    { 
     return ProvincialTaxRate * subtotal + FederalTaxRate * subtotal; 
    } 
    decimal FederalTaxRate = new decimal(0.20f); 
} 

public class SaskatchewanTax : Tax 
{ 
    public SaskatchewanTax() 
    { 
     base.ProvincialTaxRate = new decimal(0.05f); 
    } 

} 

public class OntarioTax : Tax 
{ 
    public OntarioTax() 
    { 
     base.ProvincialTaxRate = new decimal(0.08f); 
    } 

} 

आप इंटरफेस की जरूरत है, बस इसे आधार में लागू कक्षा, और कस्टम व्यवहार/व्यवहार के लिए व्युत्पन्न कक्षाओं का उपयोग करें।

0

बस विचार के लिए भोजन - इस विधि को उचित कक्षा में रखने में क्या गलत है, और बस इसे कॉल करना?

public decimal CalculateTax(decimal subtotal, decimal provincialTaxRate, decimal federalTaxRate) { 
    return provincialTaxRate * subtotal + federalTaxRate * subtotal; 
    } 

मैं समझता हूँ कि आप प्रत्येक प्रांत के लिए एक अलग प्रांतीय दर का उपयोग करना चाहते हैं, लेकिन निश्चित रूप से है कि नहीं एक अंतरफलक कार्यान्वयन में हार्ड-कोडेड किया जाना चाहिए?

+0

यह सवाल का जवाब नहीं दे सकता है, लेकिन विशेष समस्या के लिए एक बेहतर समाधान हो सकता है। जब तक कि कुछ वास्तव में फंकी कर गणना मिश्रण में आती है। – ftvs

0

बहुत सारे अच्छे उत्तर दिए गए हैं। बस मेरे दो सेंट जोड़ने के लिए। इस तरह की एक डिजाइन पैटर्न का उपयोग करते समय:

  • एक अमूर्त वर्ग
  • चीजों को साफ करने के लिए से प्राप्त अलग वर्ग के रूप में रणनीति बनाएं: सार व्युत्पन्न आधार वर्ग में रणनीतियों के बीच सभी डुप्लिकेट कोड डाल

यदि आप कभी ऐसी परिस्थिति में भाग लेंगे जहां आपके पास राज्य कर की आवश्यकता वाले करों के लिए 10 रणनीति पैटर्न हैं, और 5 सरकारी कर का उपयोग करके, आप दो व्युत्पन्न अमूर्त वर्ग (जैसे स्टेटटेक्स और सरकारी टैक्स) बना सकते हैं, जो मुख्य सार वर्ग से प्राप्त होते हैं (कर?) और स्टेटटेक्स और सरकारी टैक्स से आप कंक्रीट कक्षाएं प्राप्त कर सकते हैं (जैसे ओन्टारियोटाक्स, ते xasTax आदि)। यदि बाद में टैक्स प्रकार में बदलाव की आवश्यकता होती है, तो आप सभी सामान्य कोड को बरकरार रखने के दौरान इसे किसी अन्य कर वर्ग से प्राप्त कर सकते हैं।

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