Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Your <code>GetDiscount</code> method is classic example of <a href="http://en.wikipedia.org/wiki/Open/closed_principle" rel="nofollow">Open/Closed principle</a> violation. When you add new book type you have to add new <code>if</code> block to <code>GetDiscount</code>.</p> <p>Better way is to use some existing techinques which allow you to add new functionality without necessity to modify existing code. For example, <a href="http://en.wikipedia.org/wiki/Composite_pattern" rel="nofollow">Composite pattern</a>. I'll write some draft implementation of composite discount evaluator. You can add new discount evaluators based on any book proerties (date, price, etc.) easily.</p> <p>Also, I'll use interfaces instead of inheritance. Inheritance is a very strong link between two entities and in this case it is excessive.</p> <p>Listing is 167 lines long, so here is more comfort <a href="http://pastebin.com/SyM0cK6u" rel="nofollow">pastebin copy</a></p> <pre><code>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&lt;IDiscountEvaluator&gt; evaluators; public CompositeDiscountEvaluator() { evaluators = new List&lt;IDiscountEvaluator&gt;(); } public void AddEvaluator(IDiscountEvaluator evaluator) { evaluators.Add(evaluator); } public bool CanEvaluate&lt;TGenre&gt;(IBook&lt;TGenre&gt; book) { return evaluators.Any(e =&gt; e.CanEvaluate(book)); } public int GetDiscount&lt;TGenre&gt;(IBook&lt;TGenre&gt; book) { if (!CanEvaluate(book)) throw new ArgumentException("No suitable evaluator"); return evaluators.Where(e =&gt; e.CanEvaluate(book)).Select(e =&gt; e.GetDiscount(book)).Max(); } } interface IDiscountEvaluator { bool CanEvaluate&lt;TGenre&gt;(IBook&lt;TGenre&gt; book); int GetDiscount&lt;TGenre&gt;(IBook&lt;TGenre&gt; book); } class ReadingBookDiscountEvaluator : IDiscountEvaluator { private readonly IDictionary&lt;ReadingBooksGenre, int&gt; discounts; public ReadingBookDiscountEvaluator() { discounts = new Dictionary&lt;ReadingBooksGenre, int&gt; { {ReadingBooksGenre.Fiction, 3}, {ReadingBooksGenre.NonFiction, 4} }; } public bool CanEvaluate&lt;TGenre&gt;(IBook&lt;TGenre&gt; book) { return book is ReadingBook; } public int GetDiscount&lt;TGenre&gt;(IBook&lt;TGenre&gt; book) { var readingBook = (ReadingBook) book; return readingBook.Genres.Select(g =&gt; discounts[g]).Max(); } } class TextBookDiscountEvaluator : IDiscountEvaluator { private readonly IDictionary&lt;TextBooksGenre, int&gt; discounts; public TextBookDiscountEvaluator() { discounts = new Dictionary&lt;TextBooksGenre, int&gt; { {TextBooksGenre.Math, 1}, {TextBooksGenre.Science, 2} }; } public bool CanEvaluate&lt;TGenre&gt;(IBook&lt;TGenre&gt; book) { return book is TextBook; } public int GetDiscount&lt;TGenre&gt;(IBook&lt;TGenre&gt; book) { var textBook = (TextBook) book; return textBook.Genres.Select(g =&gt; discounts[g]).Max(); } } interface IBook&lt;TGenre&gt; { int Price { get; set; } DateTime Date { get; set; } TGenre[] Genres { get; set; } } class ReadingBook : IBook&lt;ReadingBooksGenre&gt; { public int Price { get; set; } public DateTime Date { get; set; } public ReadingBooksGenre[] Genres { get; set; } } class TextBook : IBook&lt;TextBooksGenre&gt; { public int Price { get; set; } public DateTime Date { get; set; } public TextBooksGenre[] Genres { get; set; } } enum TextBooksGenre { Math, Science } public enum ReadingBooksGenre { Fiction, NonFiction } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload