2010-05-07 11 views
9

मैंने पहले इस प्रश्न का एक संस्करण पूछने की कोशिश की है। मुझे कुछ सहायक उत्तर मिल गए, लेकिन अभी भी कुछ भी नहीं जो मुझे काफी सही लगा। ऐसा लगता है कि यह वास्तव में क्रैक करने के लिए मुश्किल नहीं होना चाहिए, लेकिन मैं एक सुरुचिपूर्ण सरल समाधान खोजने में सक्षम नहीं हूं। (यहाँ मेरी पिछली पोस्ट है, लेकिन इतनी के रूप में पहले स्पष्टीकरण जो बहुत जटिल समाधान को बढ़ावा मिल रहा से प्रभावित होने की नहीं पहले प्रक्रियात्मक कोड के रूप में यहां कहा गया है समस्या को देखने के लिए प्रयास करें: Design pattern for cost calculator app?)पॉलिमॉर्फिज्म रिफैक्टरिंग या इसी तरह के सशर्त को बदलें?

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

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

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

मुख्य लक्ष्य केवल एक स्थान (ढीला युग्मन आदि) में बदलना होगा यदि मैं एक नया paramete जोड़ना चाहता था आर (एक और आकार, जैसे XSMALL, और/या एक अन्य सेवा, जैसे "प्रशासन") कहें। यहां प्रक्रियात्मक कोड उदाहरण है:

public class Conditional 
{ 
    private int _numberOfManuals; 
    private string _serviceType; 
    private const int SMALL = 2; 
    private const int MEDIUM = 8; 

    public int GetHours() 
    { 
     if (_numberOfManuals <= SMALL) 
     { 
      if (_serviceType == "writing") 
       return 30 * _numberOfManuals; 
      if (_serviceType == "analysis") 
       return 10; 
     } 
     else if (_numberOfManuals <= MEDIUM) 
     { 
      if (_serviceType == "writing") 
       return (SMALL * 30) + (20 * _numberOfManuals - SMALL); 
      if (_serviceType == "analysis") 
       return 20; 
     } 
     else //i.e. LARGE 
     { 
      if (_serviceType == "writing") 
       return (SMALL * 30) + (20 * (MEDIUM - SMALL)) + (10 * _numberOfManuals - MEDIUM); 
      if (_serviceType == "analysis") 
       return 30; 
     } 
     return 0; //Just a default fallback for this contrived example 
    } 
} 

सभी उत्तरों की सराहना की जाती है! (लेकिन जैसा कि मैंने अपनी पिछली पोस्ट में कहा था, मैं केवल "इस पैटर्न को आजमाएं" की बजाय वास्तविक कोड उदाहरणों की सराहना करता हूं, क्योंकि जैसा कि मैंने उल्लेख किया है, वही है जो मुझे परेशानी हो रही है ...) मुझे उम्मीद है कि किसी के पास वास्तव में एक शानदार समाधान है इस समस्या यह है कि मैं वास्तव में शुरू से ही सोचा था कि वास्तव में आसान होगा ... के

============================= ===========================

नए सदस्य:

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

कोड यह रहा:

public class Service 
{ 
    protected HourCalculatingStrategy _calculatingStrategy; 
    public int NumberOfProducts { get; set; } 
    public const int SMALL = 3; 
    public const int MEDIUM = 9; 
    public const int LARGE = 20; 
    protected string _serviceType; 
    protected Dictionary<string, decimal> _reuseLevels; 

    protected Service(int numberOfProducts) 
    { 
     NumberOfProducts = numberOfProducts; 
    } 

    public virtual decimal GetHours() 
    { 
     decimal hours = _calculatingStrategy.GetHours(NumberOfProducts, _serviceType); 
     return hours; 
    } 
} 

public class WritingService : Service 
{ 
    public WritingService(int numberOfProducts) 
     : base(numberOfProducts) 
    { 
     _calculatingStrategy = new VariableCalculatingStrategy(); 
     _serviceType = "writing"; 
    } 
} 

class AnalysisService : Service 
{ 
    public AnalysisService(int numberOfProducts) 
     : base(numberOfProducts) 
    { 
     _calculatingStrategy = new FixedCalculatingStrategy(); 
     _serviceType = "analysis"; 
    } 
} 

public abstract class HourCalculatingStrategy 
{ 
    public abstract int GetHours(int numberOfProducts, string serviceType); 

    protected int GetHourRate(string serviceType, Size size) 
    { 
     XmlDocument doc = new XmlDocument(); 
     doc.Load("calculatorData.xml"); 
     string result = doc.SelectSingleNode(string.Format("//*[@type='{0}']/{1}", serviceType, size)).InnerText; 
     return int.Parse(result); 
    } 
    protected Size GetSize(int index) 
    { 
     if (index < Service.SMALL) 
      return Size.small; 
     if (index < Service.MEDIUM) 
      return Size.medium; 
     if (index < Service.LARGE) 
      return Size.large; 
     return Size.xlarge; 
    } 
} 

public class VariableCalculatingStrategy : HourCalculatingStrategy 
{ 
    public override int GetHours(int numberOfProducts, string serviceType) 
    { 
     int hours = 0; 
     for (int i = 0; i < numberOfProducts; i++) 
     { 
      hours += GetHourRate(serviceType, GetSize(i + 1)); 
     } 
     return hours; 
    } 
} 

public class FixedCalculatingStrategy : HourCalculatingStrategy 
{ 
    public override int GetHours(int numberOfProducts, string serviceType) 
    { 
     return GetHourRate(serviceType, GetSize(numberOfProducts)); 
    } 
} 

और एक साधारण उदाहरण के रूप में है कि यह कॉल (मुझे लगता है कि मैं भी सेवा वस्तुओं से युक्त एक शब्दकोश के साथ एक आवरण परियोजना वर्ग हो सकता था, लेकिन मुझे लगता है कि करने के लिए नहीं मिला है):

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     List<int> quantities = new List<int>(); 

     for (int i = 0; i < 100; i++) 
     { 
      quantities.Add(i); 
     } 
     comboBoxNumberOfProducts.DataSource = quantities; 
    } 


    private void CreateProject() 
    { 
     int numberOfProducts = (int)comboBoxNumberOfProducts.SelectedItem; 
     Service writing = new WritingService(numberOfProducts); 
     Service analysis = new AnalysisService(numberOfProducts); 

     labelWriterHours.Text = writing.GetHours().ToString(); 
     labelAnalysisHours.Text = analysis.GetHours().ToString(); 
    } 
    private void comboBoxNumberOfProducts_SelectedIndexChanged(object sender, EventArgs e) 
    { 
     CreateProject(); 
    } 

} 

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

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

ServiceType छोटे मध्यम बड़े

लेखन विश्लेषण 56 104 200

(सीधे शब्दों में यहां "टेबल" के रूप में स्वरूपित है, हालांकि कॉलम काफी गठबंधन नहीं हैं ... हालांकि मैं डेटाबेस डिज़ाइन पर सबसे अच्छा नहीं हूं, और शायद इसे अलग-अलग किया जाना चाहिए, लेकिन आपको विचार मिल रहा है ...)

कृपया मुझे बताएं कि आप क्या सोचते हैं!

+1

यह एक छोटे से परिवर्तन है, और वास्तव में अपने व्यापक पैटर्न सवाल के किसी भी उत्तर नहीं मिलता है, लेकिन आप, "लेखन" मामले में, रिकर्सिवली समारोह आह्वान सकता: 'वापसी GetHours (SMALL) + 20 * _numberOfManuals - लघु); 'जब आप XSMALL जोड़ना चाहते हैं, तो यह आपकी सहायता करता है, और तर्कसंगत रूप से अधिक स्पष्ट रूप से पढ़ता है। –

+1

+1 मुझे यह पसंद है जब लोग स्वच्छ कोड लिखने के बारे में भावुक हैं –

उत्तर

5

मैं एक गणना ProjectSize {Small, Medium, Large} के साथ शुरू करना चाहूंगा और उचित संख्या को वापस करने के लिए एक सामान्य कार्य शुरू कर दूंगा। वहां से, मैं अलग-अलग ServiceHourCalculators, WritingServiceHourCalculator और AnalysisServiceHourCalculator लिखूंगा (क्योंकि उनका तर्क पर्याप्त रूप से अलग है)। प्रत्येक एक संख्या OfManuals, एक परियोजना आकार, और घंटों की संख्या वापस ले जाएगा। मैं शायद ServiceHourCalculator को स्ट्रिंग से एक नक्शा बना सकते हैं, तो मैं कह सकते हैं:

ProjectSize projectSize = getProjectSize(_numberOfManuals); 
int hours = serviceMap.getService(_serviceType).getHours(projectSize, _numberOfManuals); 

इस तरह, जब मैं एक नई परियोजना आकार कहा, संकलक प्रत्येक सेवा के लिए कुछ बिना क्रिया मामलों पर भी मुंह जाएगा। यह सब एक ही स्थान पर नहीं संभाला जाता है, लेकिन इसे फिर से संकलित करने से पहले इसे संभाला जाता है, और मुझे बस इतना ही चाहिए।

अद्यतन मैं जावा, नहीं सी # (बहुत अच्छी तरह से) पता है, तो यह 100% सही नहीं किया जा सकता है, लेकिन नक्शे बनाने कुछ इस तरह होगा:

Map<String, ServiceHourCalculator> serviceMap = new HashMap<String, ServiceHourCalculator>(); 
serviceMap.put("writing", new WritingServiceHourCalculator()); 
serviceMap.put("analysis", new AnalysisServiceHourCalculator()); 
+1

+1 मुझे यह पसंद है - जूता-सुबह के बजाय एक पैटर्न में एक प्रतिक्रियाशील समाधान की दिशा में वृद्धिशील कदम –

+0

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

+0

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

2

एक अच्छी शुरुआत होगी एक विधि में सशर्त बयान निकालने के लिए (हालांकि केवल एक छोटी सी विधि) और इसे वास्तव में स्पष्ट नाम दें। फिर तर्क के भीतर तर्क को अपने तरीके से निकालें - फिर वास्तव में स्पष्ट नामों के साथ। (चिंता न करें अगर विधि के नाम लंबे हैं - जब तक वे जो कहते हैं वे करते हैं)

मैं इसे कोड में लिखूंगा लेकिन आपके नामों को चुनना बेहतर होगा।

मैं फिर अधिक जटिल रिफैक्टरिंग विधियों और पैटर्न पर आगे बढ़ूंगा। केवल तभी जब आप विधि कॉल की एक श्रृंखला को देखते हैं तो यह लागू पैटर्न आदि शुरू करने के लिए उचित लगेगा ..

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

संपादित करें: तो स्पष्ट करने के लिए - आप अपने अगर बयान की तरह लग रही प्राप्त करने का लक्ष्य रखना चाहिए इस

if(isBox()) 
{ 
    doBoxAction(); 
} 
else if(isSquirrel()) 
{ 
    doSquirrelAction(); 
} 

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

+0

ठीक है, मुझे लगता है कि मैं जानता हूं कि आपका क्या मतलब है, लेकिन क्या आप कोड में एक छोटा सा उदाहरण दे सकते हैं, इसलिए मैंने गलत समझा नहीं है? – Anders

+0

ठीक है, स्पष्टीकरण के लिए धन्यवाद। फिर भी, जैसा कि मैंने उल्लेख किया है, उदाहरण स्पष्टता के लिए विकसित किया गया है - इसे एक प्रक्रियात्मक तरीके से समझाते हुए जिसमें मैं इसे कभी नहीं लिखूंगा, केवल ऑब्जेक्ट उन्मुख समाधानों के उद्देश्य (कोई इरादा नहीं) देखने के लिए। – Anders

1

यह एक आम समस्या है, कुछ विकल्प हैं जिन्हें मैं सोच सकता हूं। दो डिज़ाइन पैटर्न हैं जो ध्यान में आते हैं, सबसे पहले Strategy Pattern और दूसरी बार Factory Pattern। रणनीति पैटर्न के साथ किसी ऑब्जेक्ट में गणना को समाहित करना संभव है, उदाहरण के लिए आप अलग-अलग कक्षाओं में अपनी गेटहॉर्स विधि को समाहित कर सकते हैं, प्रत्येक आकार के आधार पर गणना का प्रतिनिधित्व करेगा। एक बार जब हमने विभिन्न गणना रणनीतियों को परिभाषित किया है तो हम एक कारखाने में लपेटते हैं। गेटहॉर्स विधि में आपके अगर कथन की तरह गणना करने की रणनीति का चयन करने के लिए कारखाना जिम्मेदार होगा। किसी भी तरह से नीचे दिए गए कोड को देखें और देखें कि आप क्या सोचते हैं

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

class Program 
{ 
    static void Main(string[] args) 
    { 
     var factory = new HourCalculationStrategyFactory(); 
     var strategy = factory.CreateStrategy(1, "writing"); 

     Console.WriteLine(strategy.Calculate()); 
    } 
} 

public class HourCalculationStrategy 
{ 
    public const int Small = 2; 
    public const int Medium = 8; 

    private readonly string _serviceType; 
    private readonly int _numberOfManuals; 

    public HourCalculationStrategy(int numberOfManuals, string serviceType) 
    { 
     _serviceType = serviceType; 
     _numberOfManuals = numberOfManuals; 
    } 

    public int Calculate() 
    { 
     return this.CalculateImplementation(_numberOfManuals, _serviceType); 
    } 

    protected virtual int CalculateImplementation(int numberOfManuals, string serviceType) 
    { 
     if (serviceType == "writing") 
      return (Small * 30) + (20 * (Medium - Small)) + (10 * numberOfManuals - Medium); 
     if (serviceType == "analysis") 
      return 30; 

     return 0; 
    } 
} 

public class SmallHourCalculationStrategy : HourCalculationStrategy 
{ 
    public SmallHourCalculationStrategy(int numberOfManuals, string serviceType) : base(numberOfManuals, serviceType) 
    { 
    } 

    protected override int CalculateImplementation(int numberOfManuals, string serviceType) 
    { 
     if (serviceType == "writing") 
      return 30 * numberOfManuals; 
     if (serviceType == "analysis") 
      return 10; 

     return 0; 
    } 
} 

public class MediumHourCalculationStrategy : HourCalculationStrategy 
{ 
    public MediumHourCalculationStrategy(int numberOfManuals, string serviceType) : base(numberOfManuals, serviceType) 
    { 
    } 

    protected override int CalculateImplementation(int numberOfManuals, string serviceType) 
    { 
     if (serviceType == "writing") 
      return (Small * 30) + (20 * numberOfManuals - Small); 
     if (serviceType == "analysis") 
      return 20; 

     return 0; 
    } 
} 

public class HourCalculationStrategyFactory 
{ 
    public HourCalculationStrategy CreateStrategy(int numberOfManuals, string serviceType) 
    { 
     if (numberOfManuals <= HourCalculationStrategy.Small) 
     { 
      return new SmallHourCalculationStrategy(numberOfManuals, serviceType); 
     } 

     if (numberOfManuals <= HourCalculationStrategy.Medium) 
     { 
      return new MediumHourCalculationStrategy(numberOfManuals, serviceType); 
     } 

     return new HourCalculationStrategy(numberOfManuals, serviceType); 
    } 
} 
+0

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

1

मैं एक रणनीति पैटर्न व्युत्पन्न के साथ जाना होगा के लिए। यह अतिरिक्त कक्षाओं को जोड़ता है, लेकिन लंबी दौड़ में अधिक रखरखाव योग्य है।

public class Conditional 
{ 
    private int _numberOfManuals; 
    private string _serviceType; 
    public const int SMALL = 2; 
    public const int MEDIUM = 8; 
    public int NumberOfManuals { get { return _numberOfManuals; } } 
    public string ServiceType { get { return _serviceType; } } 
    private Dictionary<int, IResult> resultStrategy; 

    public Conditional(int numberOfManuals, string serviceType) 
    { 
     _numberOfManuals = numberOfManuals; 
     _serviceType = serviceType; 
     resultStrategy = new Dictionary<int, IResult> 
     { 
       { SMALL, new SmallResult() }, 
       { MEDIUM, new MediumResult() }, 
       { MEDIUM + 1, new LargeResult() } 
     }; 
    } 

    public int GetHours() 
    { 
     return resultStrategy.Where(k => _numberOfManuals <= k.Key).First().Value.GetResult(this); 
    } 
} 

public interface IResult 
{ 
    int GetResult(Conditional conditional); 
} 

public class SmallResult : IResult 
{ 
    public int GetResult(Conditional conditional) 
    { 
     return conditional.ServiceType.IsWriting() ? WritingResult(conditional) : AnalysisResult(conditional); ; 
    } 

    private int WritingResult(Conditional conditional) 
    { 
     return 30 * conditional.NumberOfManuals; 
    } 

    private int AnalysisResult(Conditional conditional) 
    { 
     return 10; 
    } 
} 

public class MediumResult : IResult 
{ 
    public int GetResult(Conditional conditional) 
    { 
     return conditional.ServiceType.IsWriting() ? WritingResult(conditional) : AnalysisResult(conditional); ; 
    } 

    private int WritingResult(Conditional conditional) 
    { 
     return (Conditional.SMALL * 30) + (20 * conditional.NumberOfManuals - Conditional.SMALL); 

    } 

    private int AnalysisResult(Conditional conditional) 
    { 
     return 20; 
    } 
} 

public class LargeResult : IResult 
{ 
    public int GetResult(Conditional conditional) 
    { 
     return conditional.ServiceType.IsWriting() ? WritingResult(conditional) : AnalysisResult(conditional); ; 
    } 

    private int WritingResult(Conditional conditional) 
    { 
     return (Conditional.SMALL * 30) + (20 * (Conditional.MEDIUM - Conditional.SMALL)) + (10 * conditional.NumberOfManuals - Conditional.MEDIUM); 

    } 

    private int AnalysisResult(Conditional conditional) 
    { 
     return 30; 
    } 
} 

public static class ExtensionMethods 
{ 
    public static bool IsWriting(this string value) 
    { 
     return value == "writing"; 
    } 
} 
+0

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

2

आप फैक्टरी की जरूरत नहीं है अपने उपवर्गों खुद को वे क्या के लिए चार्ज करना चाहते हैं पर फ़िल्टर कर: इसके अलावा, वहाँ अभी भी यहाँ पुनर्रचना के लिए opporunities हैं कि ध्यान में रखना।

class Project { 
    TaskType Type { get; set; } 
    int? NumberOfHours { get; set; } 
} 

आप आसानी से नई गणना जोड़ना चाहते हैं के बाद से, आप एक इंटरफेस की जरूरत है::

IProjectHours { 
    public void SetHours(IEnumerable<Project> projects); 
} 

और, कुछ वर्गों इंटरफ़ेस को लागू करने कि एक परियोजना वर्ग अगर और कुछ नहीं डेटा रखने के लिए, की आवश्यकता है :

class AnalysisProjectHours : IProjectHours { 
    public void SetHours(IEnumerable<Project> projects) { 
     projects.Where(p => p.Type == TaskType.Analysis) 
       .Each(p => p.NumberOfHours += 30); 
    } 
} 

// Non-LINQ equivalent 
class AnalysisProjectHours : IProjectHours { 
    public void SetHours(IEnumerable<Project> projects) { 
     foreach (Project p in projects) { 
      if (p.Type == TaskType.Analysis) { 
      p.NumberOfHours += 30; 
      } 
     } 
    } 
} 

class WritingProjectHours : IProjectHours { 
    public void SetHours(IEnumerable<Project> projects) { 
     projects.Where(p => p.Type == TaskType.Writing) 
       .Skip(0).Take(2).Each(p => p.NumberOfHours += 30); 
     projects.Where(p => p.Type == TaskType.Writing) 
       .Skip(2).Take(6).Each(p => p.NumberOfHours += 20); 
     projects.Where(p => p.Type == TaskType.Writing) 
       .Skip(8).Each(p => p.NumberOfHours += 10); 
    } 
} 

// Non-LINQ equivalent 
class WritingProjectHours : IProjectHours { 
    public void SetHours(IEnumerable<Project> projects) { 
     int writingProjectsCount = 0; 
     foreach (Project p in projects) { 
      if (p.Type != TaskType.Writing) { 
      continue; 
      } 
      writingProjectsCount++; 
      switch (writingProjectsCount) { 
       case 1: case 2: 
       p.NumberOfHours += 30; 
       break; 
       case 3: case 4: case 5: case 6: case 7: case 8: 
       p.NumberOfHours += 20; 
       break; 
       default: 
       p.NumberOfHours += 10; 
       break; 
      } 
     } 
    } 
} 

class NewProjectHours : IProjectHours { 
    public void SetHours(IEnumerable<Project> projects) { 
     projects.Where(p => p.Id == null).Each(p => p.NumberOfHours += 5); 
    } 
} 

// Non-LINQ equivalent 
class NewProjectHours : IProjectHours { 
    public void SetHours(IEnumerable<Project> projects) { 
     foreach (Project p in projects) { 
      if (p.Id == null) { 
      // Add 5 additional hours to each new project 
      p.NumberOfHours += 5; 
      } 
     } 
    } 
}  

बुला कोड या तो गतिशील IProjectHours कार्यान्वयन करने वालों लोड (या उन्हें स्थिर) और फिर कर सकते हैं बस के माध्यम से Project रों की सूची चलना मी:

foreach (var h in AssemblyHelper.GetImplementors<IProjectHours>()) { 
    h.SetHours(projects); 
} 
Console.WriteLine(projects.Sum(p => p.NumberOfHours)); 
// Non-LINQ equivalent 
int totalNumberHours = 0; 
foreach (Project p in projects) { 
    totalNumberOfHours += p.NumberOfHours; 
} 
Console.WriteLine(totalNumberOfHours); 
+0

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

+0

@Anders - अब जब मैं इसके बारे में सोचता हूं, यह वास्तव में एक आगंतुक पैटर्न नहीं है। ओह अच्छा। LINQ कथन सिर्फ आपके तर्क को पढ़ने के लिए थोड़ा आसान बनाने का मेरा प्रयास है। महत्वपूर्ण बात यह है कि सशर्तयों को 'आईप्रोजेक्टहॉर्स' के साथ बदल दिया गया है जो जानते हैं कि किस प्रकार के 'परियोजना' के लिए वे उपयुक्त हैं। यह उसी स्थान पर फ़िल्टर (सशर्त) और क्रिया (# घंटे का समय) रखता है। –

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