2012-12-01 28 views
5

मैं एक पुस्तक लाइब्रेरी ऐप बना रहा हूं, मेरे पास एक अमूर्त पुस्तक कक्षा है, दो प्रकार की व्युत्पन्न किताबें और दो एम्स जो पुस्तक की शैली को बचाएंगे। प्रत्येक पुस्तक एक शैली या उससे अधिक से संबंधित हो सकती है।2 व्युत्पन्न कक्षाओं से एम्स की सही सूची का चयन

abstract public class Book 
    { 
     public int Price { get; set; } 
     ... 
    } 

    public enum ReadingBooksGenre 
    { 
     Fiction, 
     NonFiction 
    } 

    public enum TextBooksGenre 
    { 
     Math, 
     Science 
    } 

    abstract public class ReadingBook : Book 
    { 
     public List<ReadingBooksGenre> Genres { get; set; } 
    } 

    abstract public class TextBook : Book 
    { 
     public List<TextBooksGenre> Genres { get; set; } 
    } 

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

private int GetDiscount(Book b) 
    { 
     int maxDiscount = 0; 
     if (b is ReadingBook) 
     { 
      foreach (var genre in (b as ReadingBook).Genres) 
      { 
       // checking if the genre is in discount, and if its bigger than other discounts. 
       if (_readingBooksDiscounts.ContainsKey(genre) && _readingBooksDiscounts[genere]>maxDiscount) 
       { 
        maxDiscount = _readingBooksDiscounts[genere]; 
       } 
      } 
     } 
     else if (b is TextBook) 
     { 
      foreach (var genre in (b as TextBook).Genres) 
      { 
       if (_textBooksDiscounts.ContainsKey(genre) && _textBooksDiscounts[genere]>maxDiscount) 
       { 
        maxDiscount = _textBooksDiscounts[genere]; 
       } 
      } 
     } 
     return maxDiscount; 
    } 

वें है:

Dictionary<ReadingBooksGenre, int> _readingBooksDiscounts; 
    Dictionary<TextBooksGenre, int> _textBooksDiscounts; 

तो अब मैं उच्चतम छूट खोजने के लिए प्रत्येक पुस्तक की शैली जांच करने की आवश्यकता है, वहाँ यह करने के लिए किसी भी बेहतर तरीका है प्रकार की जांच किए बिना सही शब्दकोश का चयन करने का कोई तरीका है? या यहां तक ​​कि शब्दकोशों के बिना इसे करने का एक तरीका, या एक का उपयोग कर? शायद किसी भी तरह से एनम के साथ पुस्तक प्रकार कनेक्ट करें?

सुधार के लिए कोई सुझाव सुनकर खुशी होगी।

(अधिक किताबें नाम, तारीख और लेखक के आधार पर छूट का एक बहुत है यही कारण है कि इस तरह से मेरे लिए सही नहीं लगता नहीं है। यहां तक ​​कि कुछ और अधिक पुस्तक प्रकार)

धन्यवाद।

+1

मैं ऐसे मॉडल का थोड़ा सा झुकाव हूं जहां टेक्स्टबुक _aren't_ गैर-कथा का उप-समूह है। हालांकि मुझे लगता है कि किसी को जे के के रोलिंग के _ क्विडिच थ्रू द एज्स के लिए भत्ते बनाना चाहिए _... –

उत्तर

1

आपकी GetDiscount विधि Open/Closed principle उल्लंघन का क्लासिक उदाहरण है। जब आप नई पुस्तक प्रकार जोड़ते हैं तो आपको if ब्लॉक GetDiscount पर जोड़ना होगा।

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

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

लिस्टिंग 167 लाइनों लंबा है, इसलिए यहाँ अधिक आराम pastebin copy

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main() 
     { 
      var compositeDiscountEvaluator = ConfigureEvaluator(); 
      var scienceBook = new TextBook 
           { 
            Date = DateTime.Now, 
            Price = 100, 
            Genres = new[] {TextBooksGenre.Math} 
           }; 
      var textBook = new TextBook 
           { 
            Date = DateTime.Now, 
            Price = 100, 
            Genres = new[] {TextBooksGenre.Math, TextBooksGenre.Science} 
           }; 
      var fictionBook = new ReadingBook 
         { 
          Date = DateTime.Now, 
          Price = 200, 
          Genres = new[] {ReadingBooksGenre.Fiction} 
         }; 
      var readingBook = new ReadingBook 
            { 
             Date = DateTime.Now, 
             Price = 300, 
             Genres = new[] {ReadingBooksGenre.Fiction, ReadingBooksGenre.NonFiction} 
            }; 
      Console.WriteLine(compositeDiscountEvaluator.GetDiscount(scienceBook)); 
      Console.WriteLine(compositeDiscountEvaluator.GetDiscount(textBook)); 
      Console.WriteLine(compositeDiscountEvaluator.GetDiscount(fictionBook)); 
      Console.WriteLine(compositeDiscountEvaluator.GetDiscount(readingBook)); 
     } 

     private static IDiscountEvaluator ConfigureEvaluator() 
     { 
      var evaluator = new CompositeDiscountEvaluator(); 
      evaluator.AddEvaluator(new ReadingBookDiscountEvaluator()); 
      evaluator.AddEvaluator(new TextBookDiscountEvaluator()); 
      return evaluator; 
     } 
    } 

    class CompositeDiscountEvaluator : IDiscountEvaluator 
    { 
     private readonly ICollection<IDiscountEvaluator> evaluators; 

     public CompositeDiscountEvaluator() 
     { 
      evaluators = new List<IDiscountEvaluator>(); 
     } 

     public void AddEvaluator(IDiscountEvaluator evaluator) 
     { 
      evaluators.Add(evaluator); 
     } 

     public bool CanEvaluate<TGenre>(IBook<TGenre> book) 
     { 
      return evaluators.Any(e => e.CanEvaluate(book)); 
     } 

     public int GetDiscount<TGenre>(IBook<TGenre> book) 
     { 
      if (!CanEvaluate(book)) 
       throw new ArgumentException("No suitable evaluator"); 
      return evaluators.Where(e => e.CanEvaluate(book)).Select(e => e.GetDiscount(book)).Max(); 
     } 
    } 

    interface IDiscountEvaluator 
    { 
     bool CanEvaluate<TGenre>(IBook<TGenre> book); 
     int GetDiscount<TGenre>(IBook<TGenre> book); 
    } 

    class ReadingBookDiscountEvaluator : IDiscountEvaluator 
    { 
     private readonly IDictionary<ReadingBooksGenre, int> discounts; 

     public ReadingBookDiscountEvaluator() 
     { 
      discounts = new Dictionary<ReadingBooksGenre, int> 
          { 
           {ReadingBooksGenre.Fiction, 3}, 
           {ReadingBooksGenre.NonFiction, 4} 
          }; 
     } 

     public bool CanEvaluate<TGenre>(IBook<TGenre> book) 
     { 
      return book is ReadingBook; 
     } 

     public int GetDiscount<TGenre>(IBook<TGenre> book) 
     { 
      var readingBook = (ReadingBook) book; 
      return readingBook.Genres.Select(g => discounts[g]).Max(); 
     } 
    } 

    class TextBookDiscountEvaluator : IDiscountEvaluator 
    { 
     private readonly IDictionary<TextBooksGenre, int> discounts; 

     public TextBookDiscountEvaluator() 
     { 
      discounts = new Dictionary<TextBooksGenre, int> 
          { 
           {TextBooksGenre.Math, 1}, 
           {TextBooksGenre.Science, 2} 
          }; 
     } 

     public bool CanEvaluate<TGenre>(IBook<TGenre> book) 
     { 
      return book is TextBook; 
     } 

     public int GetDiscount<TGenre>(IBook<TGenre> book) 
     { 
      var textBook = (TextBook) book; 
      return textBook.Genres.Select(g => discounts[g]).Max(); 
     } 
    } 

    interface IBook<TGenre> 
    { 
     int Price { get; set; } 
     DateTime Date { get; set; } 
     TGenre[] Genres { get; set; } 
    } 

    class ReadingBook : IBook<ReadingBooksGenre> 
    { 
     public int Price { get; set; } 
     public DateTime Date { get; set; } 
     public ReadingBooksGenre[] Genres { get; set; } 
    } 

    class TextBook : IBook<TextBooksGenre> 
    { 
     public int Price { get; set; } 
     public DateTime Date { get; set; } 
     public TextBooksGenre[] Genres { get; set; } 
    } 

    enum TextBooksGenre 
    { 
     Math, 
     Science 
    } 

    public enum ReadingBooksGenre 
    { 
     Fiction, 
     NonFiction 
    } 
} 
0

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

0

यह मेरे लिए प्रतीत होता है कि आपके सिस्टम में "शैली" की अवधारणा एक सरल enum लिए बहुत ही जटिल है। मैं अवधारणा को अपनी कक्षा पदानुक्रम में बढ़ावा दूंगा:

public class Genre 
{ 
    public int Discount { get; set; } 
} 
public class ReadingBooksGenre : Genre { } 
public class TextBooksGenre : Genre { } 

abstract public class Book<T> where T : Genre 
{ 
    public List<T> Genres { get; set; } 
    public int Discount 
    { 
     get 
     { 
      return (Genres.Count == 0) ? 0 : Genres.Max(g => g.Discount); 
     } 
    } 
} 
abstract public class ReadingBook : Book<ReadingBooksGenre> { } 
abstract public class TextBook : Book<TextBooksGenre> { } 

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

  • कोई संबंधित समस्या नहीं^_^