From a6759ea84bb606f0e3ec2594cbf7a65f6459aa1f Mon Sep 17 00:00:00 2001 From: salar Date: Wed, 20 Mar 2024 09:43:45 +0330 Subject: [PATCH] Add RuleEngine sample --- .../RuleEngine/Dto/PriceDto.cs | 11 +++++ .../RuleEngine/Entity/Product.cs | 16 ++++++++ .../RuleEngine/Entity/ProductSource.cs | 13 ++++++ .../RuleEngine/Entity/Source.cs | 11 +++++ .../RuleEngine/Infra/PriceRuleEngine.cs | 32 +++++++++++++++ .../RuleEngine/Infra/PriceRules/AmazonRule.cs | 20 ++++++++++ .../Infra/PriceRules/DecathlonRule.cs | 20 ++++++++++ .../Infra/PriceRules/DigiKalaRule.cs | 20 ++++++++++ .../RuleEngine/Infra/PriceRules/TorobRule.cs | 20 ++++++++++ .../Infra/PriceRules/TrendyolRule.cs | 20 ++++++++++ .../RuleEngine/Interface/IPriceRule.cs | 12 ++++++ .../RuleEngine/Program.cs | 40 ++++++++++++++++++- 12 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Dto/PriceDto.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Entity/Product.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Entity/ProductSource.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Entity/Source.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRuleEngine.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/AmazonRule.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/DecathlonRule.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/DigiKalaRule.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/TorobRule.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/TrendyolRule.cs create mode 100644 Behavioral/ChainOfResponsibility/RuleEngine/Interface/IPriceRule.cs diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Dto/PriceDto.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Dto/PriceDto.cs new file mode 100644 index 0000000..e28cf87 --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Dto/PriceDto.cs @@ -0,0 +1,11 @@ +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity; + +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Dto +{ + public record PriceModel + { + public decimal Price { get; set; } + + public Source Source { get; set; } + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Entity/Product.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Entity/Product.cs new file mode 100644 index 0000000..0b4521e --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Entity/Product.cs @@ -0,0 +1,16 @@ +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity +{ + public class Product + { + public Product() + { + Sources=new List(); + } + public int Id { get; set; } + + public decimal Price { get; set; } + public decimal SalePrice { get; set; } + + public ICollection Sources { get; set; } + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Entity/ProductSource.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Entity/ProductSource.cs new file mode 100644 index 0000000..efa4052 --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Entity/ProductSource.cs @@ -0,0 +1,13 @@ +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity +{ + public class ProductSource + { + public Source Source { get; set; } + + public Product Product { get; set; } + + public string Url { get; set; } + + public DateTime LastUpdatedOn { get; set; } + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Entity/Source.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Entity/Source.cs new file mode 100644 index 0000000..0c59883 --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Entity/Source.cs @@ -0,0 +1,11 @@ +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity +{ + public enum Source + { + Amazon, + Decathlon, + DigiKala, + Torob, + Trendyol + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRuleEngine.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRuleEngine.cs new file mode 100644 index 0000000..dfabaa0 --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRuleEngine.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Dto; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Interface; + +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Infra +{ + public class PriceRuleEngine + { + private readonly IEnumerable _rules; + + public PriceRuleEngine(IEnumerable rules) + { + _rules=rules; + } + + public PriceModel CalculatePrice(Product product) + { + var price=new PriceModel(); + foreach (var rule in _rules) + { + price = rule.Calculate(product, price); + } + + return price; + } + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/AmazonRule.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/AmazonRule.cs new file mode 100644 index 0000000..0d8f4f9 --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/AmazonRule.cs @@ -0,0 +1,20 @@ +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Dto; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Interface; + +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Infra.PriceRules +{ + public class AmazonRule : IPriceRule + { + public int Priority { get; set; } = 1; + public PriceModel Calculate(Product product, PriceModel price) + { + //fetch the price from Amazon and get the lower price + return new PriceModel + { + Source = Source.Amazon, + Price = 19_000 + }; + } + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/DecathlonRule.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/DecathlonRule.cs new file mode 100644 index 0000000..749ea2e --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/DecathlonRule.cs @@ -0,0 +1,20 @@ +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Dto; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Interface; + +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Infra.PriceRules +{ + public class DecathlonRule : IPriceRule + { + public int Priority { get; set; } = 2; + public PriceModel Calculate(Product product, PriceModel price) + { + //fetch the price from Decathlon and get the lower price + return new PriceModel + { + Source = Source.Decathlon, + Price = 16_000 + }; + } + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/DigiKalaRule.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/DigiKalaRule.cs new file mode 100644 index 0000000..46a8810 --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/DigiKalaRule.cs @@ -0,0 +1,20 @@ +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Dto; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Interface; + +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Infra.PriceRules +{ + public class DigiKalaRule : IPriceRule + { + public int Priority { get; set; } = 3; + public PriceModel Calculate(Product product, PriceModel price) + { + //fetch the price from DigiKala and get the lower price + return new PriceModel + { + Source = Source.DigiKala, + Price = 15_000 + }; + } + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/TorobRule.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/TorobRule.cs new file mode 100644 index 0000000..955d8cd --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/TorobRule.cs @@ -0,0 +1,20 @@ +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Dto; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Interface; + +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Infra.PriceRules +{ + public class TorobRule : IPriceRule + { + public int Priority { get; set; } = 4; + public PriceModel Calculate(Product product, PriceModel price) + { + //fetch the price from Torob and get the lower price + return new PriceModel + { + Source = Source.Torob, + Price = 10_000 + }; + } + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/TrendyolRule.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/TrendyolRule.cs new file mode 100644 index 0000000..1942d08 --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Infra/PriceRules/TrendyolRule.cs @@ -0,0 +1,20 @@ +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Dto; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Interface; + +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Infra.PriceRules +{ + public class TrendyolRule : IPriceRule + { + public int Priority { get; set; } = 2; + public PriceModel Calculate(Product product, PriceModel price) + { + //fetch the price from Trendyol and get the lower price + return new PriceModel + { + Source = Source.Trendyol, + Price = 8_000 + }; + } + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Interface/IPriceRule.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Interface/IPriceRule.cs new file mode 100644 index 0000000..4eadb47 --- /dev/null +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Interface/IPriceRule.cs @@ -0,0 +1,12 @@ +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Dto; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity; + +namespace Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Interface +{ + public interface IPriceRule + { + public int Priority { get; set; } + + PriceModel Calculate(Product product,PriceModel price); + } +} diff --git a/Behavioral/ChainOfResponsibility/RuleEngine/Program.cs b/Behavioral/ChainOfResponsibility/RuleEngine/Program.cs index 3751555..a12c7e3 100644 --- a/Behavioral/ChainOfResponsibility/RuleEngine/Program.cs +++ b/Behavioral/ChainOfResponsibility/RuleEngine/Program.cs @@ -1,2 +1,40 @@ // See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); + +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Entity; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Infra; +using Thisisnabi.DesignPattern.Behavioral.ChainOfResponsibility.RuleEngine.Interface; +using System.Reflection; + +var product = new Product +{ + Sources = new List + { + new() + { + Source = Source.Torob, + Url = "https://torob.com/.." + }, + new ProductSource + { + Source = Source.DigiKala, + Url = "https://digikala.com/.." + }, + new ProductSource + { + Source = Source.Amazon, + Url = "https://Amazon.com/.." + } + } +}; +var ruleType = typeof(IPriceRule); + +var rules = Assembly.GetExecutingAssembly().GetTypes() + .Where(p => ruleType.IsAssignableFrom(p) && !p.IsInterface) + .Select(q => Activator.CreateInstance(q) as IPriceRule) + .OrderBy(p => p.Priority).ToList(); + +var engine = new PriceRuleEngine(rules); + +var result = engine.CalculatePrice(product); + +Console.WriteLine($"The lowest price is :{result.Price} and available on :{result.Source} ");