2009-04-28 16 views
6

हो सकता है मेरे पास सलाह लेने के लिए कोई अन्य डेवलपर नहीं है या "आप क्या सोचते हैं - मैं यह सोच रहा हूं" तो कृपया, अगर आपके पास है समय, एक पढ़ा है और मुझे बताओ कि आप क्या सोचते हैं।क्या मुझे ऑर्डर क्लास में शुल्क/छूट की सूची शामिल करनी चाहिए या उन्हें आइटमलाइन

वर्णन से दिखाना आसान है, लेकिन ऐप अनिवार्य रूप से 3 प्रमुख भागों के साथ बिक्री बिंदु ऐप की तरह है: आइटम, ऑर्डर इटम्स और ऑर्डर।

आइटम क्लास डेटा डेटा के रूप में डेटा है।

public class Item 
    : IComparable<OrderItem>, IEquatable<OrderItem> 
{ 
    public Int32 ID { get; set; } 
    public String Description { get; set; } 
    public decimal Cost { get; set; } 

    public Item(Int32 id, String description, decimal cost) 
    { 
     ID = id; 
     Description = description; 
     Cost = cost; 
    } 
    // Extraneous Detail Omitted 
} 

ऑर्डर आइटम क्लास ऑर्डर पर एक आइटम लाइन है।

Order order = new Order(); 
// Fee 
order.Add(new OrderItem(new Item("Admin Fee", 20), 1)); 

// Discount 
order.Add(new OrderItem(new Item("Today's Special", -5), 1)); 

मुझे यह पसंद है यह भावना और एक आधार वर्ग कि आदेश में आइटम के माध्यम से दोहराता से विरासत में आता है,:

public class OrderItem 
    : Item, IBillableItem, IComparable<OrderItem>, IEquatable<OrderItem> 
{ 
    // IBillableItem members 
    public Boolean IsTaxed { get; set; } 
    public decimal ExtendedCost { get { return Cost * Quantity; } } 

    public Int32 Quantity { get; set; } 

    public OrderItem (Item i, Int32 quantity) 
     : base(i.ID, i.Description, i.Cost) 
    { 
     Quantity = quantity; 

     IsTaxed = false; 
    } 
    // Extraneous Detail Omitted 
} 

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

एकमात्र समस्या जो मैं कर रहा हूं वह इस डेटा को प्रदर्शित कर रहा है। जिस फॉर्म पर यह चलता है वह ग्रिड होता है जहां बिक्री आइटम (यानी फीस/छूट नहीं) प्रदर्शित की जानी चाहिए। इसी तरह कुछ फीस और कुछ छूट के लिए टेक्स्टबॉक्स भी हैं। मैं इस वर्ग में फ़ील्ड में उन UI तत्वों को डेटाबेस करना चाहता हूं ताकि उपयोगकर्ता (और मुझे) पर यह आसान हो।

मेरे विचार

2 इंटरफेस है: IHasFees, IHasDiscounts और व्यवस्था उन्हें लागू है, दोनों जिनमें से सूची का एक सदस्य होगा। इस तरह, मैं केवल बिक्री वस्तुओं तक पहुंच सकता था, केवल शुल्क और केवल छूट (और आवश्यकता होने पर उन्हें नियंत्रित करने के लिए बाध्य करता हूं)। (Triplicating मैं डुप्लिकेट कर रहा हूँ - - अब मैं/3 अलग ऐड मिल गया है वर्ग (addItem/AddFee/AddDiscount/निकालें ...) के लिए विधि निकालें:

मैं इसके बारे में क्या पसंद नहीं करते?) कार्यक्षमता क्योंकि उनमें से सभी एक ही प्रकार की वस्तु की सूची हैं, बस प्रत्येक सूची का एक अलग अर्थ है।

क्या मैं सही रास्ते पर हूं? मुझे संदेह है कि ज्यादातर लोगों के लिए यह एक हल समस्या है (इस बात पर विचार करना कि इस प्रकार का सॉफ्टवेयर बहुत आम है)।

+7

IHasFees और IHasDiscounts ध्वनि LOLCats की तरह हंसते हुए। –

उत्तर

3

मैं एक ALT.net पॉडकास्ट मैं नहीं बहुत पहले की बात सुनी पर रोब कॉनरी द्वारा एक टिप्पणी करने के लिए आप बात करेंगे (मैं एक ALT.net वकील नहीं हूँ, लेकिन तर्क ध्वनि लग रहा था):

क्या एक "व्यापार उपयोगकर्ता" को समझ में आता है (यदि आपके पास उनमें से कोई भी है)।

एक प्रोग्रामर के रूप में, आप आइटम, फीस, डिस्काउंट इत्यादि में कारक बनाना चाहते हैं, क्योंकि उनके पास समान गुण और व्यवहार हैं।

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

डीआरवाई का मतलब आपके मॉडल को सीमित करने का मतलब नहीं है, और आपको इसे ध्यान में रखना चाहिए जब विरासत या विरासत के माध्यम से फैक्टरिंग व्यवहार।

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

हालांकि यह प्रथाओं, स्वाद और राय की बात है, तो आँख बंद करके सलाह एक वेब साइट पर पोस्ट का पालन नहीं करते :)

और अपने विशिष्ट समस्या के लिए, प्रणाली मैं का उपयोग करता है आइटम, फीस के साथ काम करते हैं, लाइन-आइटम छूट (आइटम की एक संपत्ति) और व्यवस्था पर एक वैश्विक छूट (हालांकि यह एक आदेश नहीं है, यह स्थिति रसीद है, लेकिन यह वास्तव में उस स्थिति में कोई फर्क नहीं पड़ता)।

मुझे लगता है कि कारण यह है कि, उन अवधारणाओं के पीछे, आइटम आविष्कारित टुकड़ों के विशिष्ट उदाहरण हैं, वे स्टॉक मात्राओं को प्रभावित करते हैं, वे संख्यात्मक और मात्रात्मक हैं।

शुल्क नहीं हैं। वे अधिकतर गुणों को साझा नहीं करते हैं।

इससे आपके मामले में कोई फर्क नहीं पड़ता, क्योंकि आपका डोमेन उससे अधिक सीमित लगता है, लेकिन आप उन मुद्दों को ध्यान में रखना चाहेंगे।

+0

+1: मुझे आपके द्वारा ऑर्डर किए जाने वाले आइटमों के रूप में छूट देखने में कठिनाई हो रही है, एक शुल्क जो मैं फैल सकता हूं लेकिन हम इसे ILineItem को परिभाषित करके मॉडल कर सकते हैं जो विवरण लागत हो सकता है & मात्रा, एक शुल्क एक शुल्क में एक लाइन आइटम हो सकता है। मैं अभी भी आइटम और डिस्काउंट से अलग के रूप में एक आदेश पर उन्हें बेनकाब कर दूंगा, भले ही कवर के तहत वे एक ही प्रकार के हों। – JoshBerke

+0

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

1

एक विकल्प अपने आदेश कक्षा में

enum ItemType 
{ 
    Item, 
    Fee, 
    Discount 
} 

अब आप कर सकते थे OrderItem करने के लिए एक itemtype विशेषता जोड़ने के लिए है:

public IList<OrderItem> Fees 
{ 
    get 
    { 
     return _items.Find(i=>i.ItemType==ItemType.Fee); 
    } 
} 

अब आप अभी भी अपने एकल सूची रखने के लिए और अतिरिक्त इंटरफेस से बच सकते हैं । आप इलिस्ट GetItems (ItemType प्रकार) जैसे एक विधि भी हो सकता है।

एक अन्य विचार यह है कि आपका वर्तमान डिज़ाइन% की छूट के लिए अनुमति नहीं देता है। आज आपको 10% छूट मिलती है। यह एक आवश्यकता नहीं हो सकती है, लेकिन इसकी गणना करने के लिए आवेदन से बचने का एक विकल्प छूट से वस्तुओं को अलग करना है।

छूट 10 नियमों को 5% बंद करने का आदेश भी अधिक नियम बन सकती है।

+0

+1 मुझे यह विचार पसंद है, और विशेष रूप से छूट के नियम बनने की अवधारणा (जैसा कि इसका उपयोग करने वाले विक्रेता में से एक अक्सर ऐसा कुछ करता है)। –

+0

हाँ, नियमों के रूप में यह काफी जटिल है लेकिन उस जटिलता के साथ आप बहुत सी अच्छी चीजें कर सकते हैं जो आप कर सकते हैं। विशेष रूप से यदि आप बिना किसी संकलन के नए नियमों को इंजेक्ट कर सकते हैं .... – JoshBerke

3

प्रभावी रूप से, मैं विवरण में अपने डिजाइन को देखो और यह पता लगाने की कोशिश करता हूँ जहां व्यवहार झूठ; फिर उन व्यवहारों में एक विशिष्ट इंटरफ़ेस में किसी भी समानता को निकालें और सुनिश्चित करें कि आपके डिज़ाइन पर लागू होता है।

बुद्धि के लिए

; शुल्क से जुड़े सत्यापन व्यवहार संबंधित हो सकते हैं। आइए मान लें कि आप किसी ऑर्डर में शुल्क जोड़ते हैं जिसमें 20 आइटम या अधिक (केवल एक यादृच्छिक उदाहरण है, इस पर मेरे साथ चलें)। अब, जब आप 20 वां आइटम जोड़ते हैं, तो आप उस शुल्क को ऑर्डर में जोड़ना चाहेंगे, लेकिन एक समस्या है; जब आप अपने ऑर्डर से कोई आइटम हटाते हैं, तो क्या आप यह देखने के लिए हर बार जांचना चाहते हैं कि आपको अपने आदेश से उस फीस को हटाना है या नहीं? मुझे शक है; यहां निहितार्थ यह है कि एक ऐसा व्यवहार है जो शुल्क/छूट से जुड़ा हुआ है जो अनिवार्य रूप से उन्हें चीजों की एक पूरी तरह से अलग वर्ग बनाता है।

मैं इसे इस तरह से देखता हूं; शुल्क और छूट को "विशेष" चीज़ों के रूप में वर्गीकृत करें, और उसके बाद एक "विशेष" इंटरफ़ेस बनाएं जिससे शुल्क और छूट दोनों प्राप्त हों। विशेष इंटरफ़ेस को किसी भी सामान्य कार्यक्षमता को निकालें (उदाहरण के लिए, "मान्य करें")। फिर अपने ऑर्डर को विशेष (या जो कुछ भी) इंटरफेस लागू करें।

इस तरह, आप विशिष्ट Fee.Validate() व्यवहार और डिस्काउंट को परिभाषित कर सकते हैं। वैध व्यवहार, और polymorphism के जादू (m_specialCollection के foreach।) को ठीक से संचालित करने के लिए धन्यवाद। इस तरह, साथ ही, आप किसी और चीज के लिए विशेष इंटरफ़ेस का विस्तार कर सकते हैं जो कि आवश्यक हो सकता है (कहें, कर)।

2

मुझे लगता है कि आप जिस समस्या का सामना कर रहे हैं उसका मूल यह है कि आपने OrderItem को Item के उप-वर्ग के रूप में लागू किया है, और अब आप यह खोज रहे हैं कि यह वास्तव में हमेशा उपयुक्त नहीं है। , क्रम संख्या की तारीख:

एक Order वर्ग कि हर एक-मान डेटा तत्व के लिए सार्वजनिक गुण है कि आप बाध्यकारी डेटा को बेनकाब करना चाहते हैं को लागू करता है बनाएँ:

आप क्या वर्णन को देखते हुए, यहाँ मैं कैसे लागू करने के लिए इस कोशिश करेंगे , ग्राहक, कुल शुल्क, कुल छूट, आदि। ऐसा लगता है कि आपको विशिष्ट शुल्क/छूट को एकल मान के रूप में प्रदर्शित करने की आवश्यकता हो सकती है; यदि हां, तो उन लोगों के लिए सार्वजनिक संपत्तियों को लागू करें।

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

के विशिष्ट प्रकार के लिए OrderItem की उपवर्गों (या वर्गों कि IOrderItem लागू) बनाएं लाइन आइटम एक आदेश पर प्रकट कर सकते हैं: ProductOrderItem, FeeOrderItem, DiscountOrderItem, आदि

ProductItem के अपने कार्यान्वयन में, Item की संपत्ति को लागू - यह कुछ इस तरह दिखाई चाहते हैं:

public class ProductItem : OrderItem 
{ 
    public Item Item { get; set; } 
    public string Description { get { return Item.Description; } } 
    public int Quantity { get; set; } 
    public decimal Amount { get { return Item.Price * Quantity; } } 
} 

सभी लाइन आइटमों को संग्रहीत करने के लिए Order के भीतर IEnumerable<OrderItem> की एक संपत्ति लागू करें। OrderItems जोड़ने के लिए एक AddItem विधि को लागू करें, जैसे:

public void AddItem(OrderItem item) 
{ 
    _Items.Add(item); // note that backing field is a List<OrderItem> 
} 

जो आप सुंदर बस फोन कर सकते हैं: उन एकल महत्वपूर्ण क्षेत्रों को इस सूची, जैसे से मान एक्सट्रैक्ट करने की जरूरत है इस बात का

Order o = new Order(); 
o.AddItem(new ProductOrderItem { Item = GetItem(1), Quantity = 2 }); 
o.AddItem(new FeeItem { Description = "Special Fee", Amount = 100 }); 
o.AddItem(new DiscountItem { DiscountAmount = .05 }); 

लिखें कार्यान्वयन:

public decimal TotalFees 
{ 
    get 
    { 
     return (from OrderItem item in Items 
       where item is FeeItem 
       select item.Amount).Sum(); 
    } 
} 

आप बाद में वापस आ सकते हैं और यदि आवश्यक हो इन गुणों का अनुकूलन (जैसे गणना बचत एक बार आप इसे एक बार किया है)।

ध्यान दें कि आप AddItem को ProductItem एस जोड़ने के लिए भी प्रतिबंधित कर सकते हैं, और अन्य प्रकार के आइटम जोड़ने के लिए Order में अन्य विधियों का उपयोग कर सकते हैं। उदाहरण के लिए, एक आदेश केवल एक ही छूट राशि हो सकती है यदि:

public void SetDiscountAmount(decimal discountAmount) 
{ 
    DiscountOrderItem item = _Items 
     .Where(x => x is DiscountOrderItem) 
     .SingleOrDefault(); 
    if (item == null) 
    { 
     item = new DiscountOrderItem(); 
     _Items.Add(item); 
    } 
    item.DiscountAmount = discountAmount; 
} 

आप इस दृष्टिकोण का उपयोग करते हैं आप मदों की ग्रिड में उचित जगह में छूट राशि प्रदर्शित करने के लिए करना चाहता था, लेकिन यह भी चाहते थे कि किसी आदेश का छूट राशि एक ही मूल्य होने के लिए।(यह विवाद-योग्य है कि आप DiscountAmountOrder की संपत्ति बनाने के लिए, अपने सेटर में DiscountOrderItem बनाते हैं, और DiscountOrderItemOrder.DiscountAmount से अपने Amount प्राप्त करना चाहते हो सकता है। मुझे लगता है कि दोनों दृष्टिकोण उनके पक्ष-विपक्ष की है।)

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

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