Advertisement
ivandrofly

Keep an Eye on SRP - That Might Just Save Your Broken Code Base

Aug 31st, 2023 (edited)
1,258
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.05 KB | None | 0 0
  1.  // https://youtu.be/vTnlFdRf1Kc
  2.  
  3. var martinFowler = new Person(10, "Martin Fowler);
  4. var server = new DemoDiscountServer(person);
  5. var book = new Book("Design Patern", new List<Person>{martinFowler});
  6. var discountApplications = server.GetDiscountAmounts(10, new DiscountContext(book))
  7.  
  8.  
  9. public interface IDiscount
  10. {
  11.      IEnumerable<DiscountApplication> GetDiscountAmounts(Money price, DiscountContext context);
  12. }
  13.  
  14. public record DiscountApplication(string Label, Money amount);
  15. public record Book(string Title, List<Person> Authors);
  16. public record DiscountContext(Book? book);
  17. public record Person(int Id, string Name);
  18.  
  19. public class DemoDiscountServer : IDiscountServer
  20. {
  21.     private readonly Person _martinFowler;
  22.    
  23.     public DemoDiscountServer(Person author) => _martinFowler = author);
  24.    
  25.     public IDiscount GetDiscounts() =>
  26.         GetPatternBooksDiscount(.30M).WhenBookAuthorBy(_martinFowler)
  27.         .OrElse(GetPatternBooksDiscount(.20M))
  28.         .OrElse(new RelativeDiscount(.10M).WhenPositivePrice().OnAllBooks());
  29.        
  30.     private Discount GetPatternBooksDiscount(decimal factor) =>
  31.         new RelativeDiscount(factor).WhenPositivePrice().WhenTitleContains("pattern");
  32. }
  33.  
  34. public static class DiscountExtensions
  35. {
  36.     public static IDiscount WhenBookAuthorBy(this IDiscount discount, Person author)
  37.     {  
  38.         return new BookAuthorDiscount(person,  discount)
  39.     }
  40.    
  41.     public static IDiscount WhenPositivePrice(this IDiscount discount) // relativeDiscount
  42.     {  
  43.         return new PositivePriceDiscount(discount)
  44.     }
  45.    
  46.     public static IDiscount WhenTitleContains(this IDiscount discount, string pattern) // relativeDiscount
  47.     {  
  48.         // the registration is done is this order
  49.         // RelativeDiscount => PositivePriceDiscount => TitleContentDiscount
  50.        
  51.         // the call will be done in this order
  52.         // RelativeDiscount <= PositivePriceDiscount <= TitleContentDiscount
  53.         return new TitleContentDiscount(pattner, discount) //
  54.     }
  55.    
  56.     public static IDiscount GetPatternBook(this IDiscount)
  57.     {  
  58.         return new RelativeDiscount(factory).WhenPositivePrice().WhenTitleContains("pattern");
  59.     }
  60.    
  61.     public static Discount OrElse(this IDiscount discount, IDiscount elseDiscount)
  62.     {
  63.         // TODO:
  64.         // has to return something that will be a ElseDiscount which will call its
  65.         // GetDiscountAmounts(..) if `discount`.GetDiscountAmounts return empty set
  66.         return elseDiscount;
  67.     }
  68.    
  69.     public static Enumerable<DiscountApplication> OnAllBooks(IDiscount discount) // PositivePriceDiscount
  70.     {
  71.         return discount.GetDiscountAmounts().WithSuffix(" on all books)";
  72.     }      
  73. }
  74.  
  75. internal static class DisocuntApplicationExtensions
  76. {
  77.     internal static IEnumerable<DiscountApplication> WithSuffix(this IEnumerable<DiscountApplication> discounts, string suffix)
  78.     {
  79.         return discounts.Select(discount => discount with {Label = discount.Label + suffix});
  80.     }
  81. }
  82.  
  83. public class RelativeDiscount : IDiscount
  84. {
  85.     public RelativeDiscountd(decimal factor) => _factor = factory > 0 && factor < 1 ? factory
  86.         : throw new ArgumentException("Multiplying factor must be positive and smaller than 1.");
  87.    
  88.     public IEnumerable<DiscountApplication> GetDiscountAmounts(Money price, DiscountContext context) =>
  89.         price == Money.Zero ? Enumerable.Empty<DisocuntApplication>() // can remove?
  90.         : new[] { new DiscountApplication($"{_factor:P2} discount", price * _factor) };
  91. }
  92.  
  93. public abstract class RestrictedDiscount : IDiscount
  94. {
  95.     private readonly IDiscount _other;
  96.     private readonly string _labelSuffix;
  97.    
  98.     protected RestrictedDiscount(IDiscount other, string labelSuffix) => (_other, _labelSuffix) => (other, labelSuffix);
  99.    
  100.     public IEnumerable<DiscountApplication> GetDiscountAmounts(Money price, DiscountContext context) =>
  101.         AppliesTo(context) ? ApplyTo(price, context).WithSuffix(_labelSuffix)
  102.         : IEnumerable.Empty<DiscountApplication>();
  103.        
  104.    
  105.     protected IEnumerable<DiscountApplication> ApplyTo(Money price, DiscountContext context) =>
  106.         _other.GetDiscountAmounts(price, context);
  107.        
  108.     protected abstract bool AppliesTo(DiscountContext context);
  109. }
  110.  
  111. public class NoDiscount : IDiscount
  112. {
  113.     public IEnumerable<DiscountApplication> GetDiscountAmounts(Money price, DiscountContext context) =>
  114.         Enumerable.Empty<DiscountAppliction>();
  115. }
  116.  
  117. public class ElseDiscount : IDiscount
  118. {
  119.     private readonly IDiscount _ifDiscount;
  120.     private readonly IDiscount _elseDicount;
  121.    
  122.     ElseDiscount(IDiscount ifDiscount, IDiscount elseDiscount) => (_ifDiscount, _elseDicount) = (ifDiscount, elseDiscount)
  123.    
  124.     public IEnumerable<DiscountApplication> GetDiscountAmounts(Money price, DiscountContext context)
  125.     {
  126.         // NOTE: I suspect this is the implementation
  127.         var appDiscounts = ifDiscount.GetDiscountAmounts(price, context).ToList();
  128.         appDiscounts.Count > 0 ? appDiscounts : elseDiscount.GetDiscountAmounts(price, context);
  129.     }
  130. }
  131.  
  132.  
  133. public class TitleContentDiscount : RestrictedDiscount
  134. {
  135.     private readonly IDiscount _other;
  136.    
  137.     public BookAuthorDiscount(string titleSubstring, IDiscount other)
  138.         :base(other, $" when by '{titleSubstring}' in the title") => _titleSubstring != string.IsNullOrEmpty(titleString) ? titleString
  139.         : throw new ArgumentException("....");
  140.    
  141.     protected override bool AppliesTo(DiscountContext context) =>
  142.         context.Book?.Title.Contains(_titleSubstring, StringComparison.InvariantCultureIgnoreCase) ?? false;
  143. }
  144.  
  145. public class BookAuthorDiscount : RestrictedDiscount
  146. {
  147.     private readonly IDiscount _other;
  148.    
  149.     public BookAuthorDiscount(Person author, IDiscount other)
  150.         :base(other, $" authored by {author.FullName}") => _author = author;
  151.    
  152.     protected override bool AppliesTo(DiscountContext context) =>
  153.         context.Book?.Authors.Any(author => author.Id => _author.Id) ?? false;
  154. }
  155.  
  156. public class PositivePriceDiscount : IDiscount
  157. {
  158.     private readonly IDiscount _other;
  159.    
  160.     public PositivePriceDiscount(IDiscount other) => _other = other;
  161.    
  162.     public IEnumerable<DiscountApplication> GetDiscountAmounts(Money price, DiscountContext context) =>
  163.         price == Money.Zero ? Enumerable.Empty<DisocuntApplication>()
  164.         : _other.GetDiscountAmounts(price, context);
  165. }
  166.  
  167. Follow on github
  168. https://github.com/ivandrofly
  169. https://x.com/ivandrofly
  170.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement