From de5a1cc31fa85bbef8a117ee427a602059e8b26c Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 10 Feb 2019 15:46:45 -0500 Subject: [PATCH 01/16] Applying SRP --- ArdalisRating/ConsoleLogger.cs | 15 ++++++++++ ArdalisRating/FilePolicySource.cs | 15 ++++++++++ ArdalisRating/RatingEngine.cs | 50 ++++++++++++++++++------------- 3 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 ArdalisRating/ConsoleLogger.cs create mode 100644 ArdalisRating/FilePolicySource.cs diff --git a/ArdalisRating/ConsoleLogger.cs b/ArdalisRating/ConsoleLogger.cs new file mode 100644 index 0000000..151d1e5 --- /dev/null +++ b/ArdalisRating/ConsoleLogger.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.IO; + +namespace ArdalisRating +{ + public class ConsoleLogger + { + public void Log(string message) + { + Console.WriteLine(message); + } + } +} diff --git a/ArdalisRating/FilePolicySource.cs b/ArdalisRating/FilePolicySource.cs new file mode 100644 index 0000000..9b1abd8 --- /dev/null +++ b/ArdalisRating/FilePolicySource.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.IO; + +namespace ArdalisRating +{ + public class FilePolicySource + { + public string GetPolicyFromSource() + { + return File.ReadAllText("policy.json"); + } + } +} diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index 0e373d3..6ee78ea 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -1,37 +1,45 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System; -using System.IO; namespace ArdalisRating { + public class JsonPolicySerializer + { + public Policy GetPolicyFromJsonString(string jsonString) + { + return JsonConvert.DeserializeObject(jsonString, + new StringEnumConverter()); + } + } /// /// The RatingEngine reads the policy application details from a file and produces a numeric /// rating value based on the details. /// public class RatingEngine { + public ConsoleLogger Logger { get; set; } = new ConsoleLogger(); + public FilePolicySource PolicySource { get; set; } = new FilePolicySource(); + public JsonPolicySerializer PolicySerializer { get; set; } = new JsonPolicySerializer(); public decimal Rating { get; set; } public void Rate() { - Console.WriteLine("Starting rate."); + Logger.Log("Starting rate."); - Console.WriteLine("Loading policy."); + Logger.Log("Loading policy."); - // load policy - open file policy.json - string policyJson = File.ReadAllText("policy.json"); + string policyJson = PolicySource.GetPolicyFromSource(); - var policy = JsonConvert.DeserializeObject(policyJson, - new StringEnumConverter()); + var policy = PolicySerializer.GetPolicyFromJsonString(policyJson); switch (policy.Type) { case PolicyType.Auto: - Console.WriteLine("Rating AUTO policy..."); - Console.WriteLine("Validating policy."); + Logger.Log("Rating AUTO policy..."); + Logger.Log("Validating policy."); if (String.IsNullOrEmpty(policy.Make)) { - Console.WriteLine("Auto policy must specify Make"); + Logger.Log("Auto policy must specify Make"); return; } if (policy.Make == "BMW") @@ -45,37 +53,37 @@ public void Rate() break; case PolicyType.Land: - Console.WriteLine("Rating LAND policy..."); - Console.WriteLine("Validating policy."); + Logger.Log("Rating LAND policy..."); + Logger.Log("Validating policy."); if (policy.BondAmount == 0 || policy.Valuation == 0) { - Console.WriteLine("Land policy must specify Bond Amount and Valuation."); + Logger.Log("Land policy must specify Bond Amount and Valuation."); return; } if (policy.BondAmount < 0.8m * policy.Valuation) { - Console.WriteLine("Insufficient bond amount."); + Logger.Log("Insufficient bond amount."); return; } Rating = policy.BondAmount * 0.05m; break; case PolicyType.Life: - Console.WriteLine("Rating LIFE policy..."); - Console.WriteLine("Validating policy."); + Logger.Log("Rating LIFE policy..."); + Logger.Log("Validating policy."); if (policy.DateOfBirth == DateTime.MinValue) { - Console.WriteLine("Life policy must include Date of Birth."); + Logger.Log("Life policy must include Date of Birth."); return; } if (policy.DateOfBirth < DateTime.Today.AddYears(-100)) { - Console.WriteLine("Centenarians are not eligible for coverage."); + Logger.Log("Centenarians are not eligible for coverage."); return; } if (policy.Amount == 0) { - Console.WriteLine("Life policy must include an Amount."); + Logger.Log("Life policy must include an Amount."); return; } int age = DateTime.Today.Year - policy.DateOfBirth.Year; @@ -95,11 +103,11 @@ public void Rate() break; default: - Console.WriteLine("Unknown policy type"); + Logger.Log("Unknown policy type"); break; } - Console.WriteLine("Rating completed."); + Logger.Log("Rating completed."); } } } From 524cde04f414123752a50a65418311219f3894f5 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Mon, 11 Feb 2019 09:28:16 -0500 Subject: [PATCH 02/16] Moved class to separate file --- ArdalisRating/JsonPolicySerializer.cs | 14 ++++++++++++++ ArdalisRating/RatingEngine.cs | 12 +----------- 2 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 ArdalisRating/JsonPolicySerializer.cs diff --git a/ArdalisRating/JsonPolicySerializer.cs b/ArdalisRating/JsonPolicySerializer.cs new file mode 100644 index 0000000..b068d75 --- /dev/null +++ b/ArdalisRating/JsonPolicySerializer.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace ArdalisRating +{ + public class JsonPolicySerializer + { + public Policy GetPolicyFromJsonString(string jsonString) + { + return JsonConvert.DeserializeObject(jsonString, + new StringEnumConverter()); + } + } +} diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index 6ee78ea..0cf5ac6 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -1,17 +1,7 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using System; +using System; namespace ArdalisRating { - public class JsonPolicySerializer - { - public Policy GetPolicyFromJsonString(string jsonString) - { - return JsonConvert.DeserializeObject(jsonString, - new StringEnumConverter()); - } - } /// /// The RatingEngine reads the policy application details from a file and produces a numeric /// rating value based on the details. From 05fd42bdc36aaab063489d3f37dbfe32366ddca7 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 10 Feb 2019 15:46:45 -0500 Subject: [PATCH 03/16] Applying SRP --- ArdalisRating/ConsoleLogger.cs | 15 ++++++++++ ArdalisRating/FilePolicySource.cs | 15 ++++++++++ ArdalisRating/RatingEngine.cs | 50 ++++++++++++++++++------------- 3 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 ArdalisRating/ConsoleLogger.cs create mode 100644 ArdalisRating/FilePolicySource.cs diff --git a/ArdalisRating/ConsoleLogger.cs b/ArdalisRating/ConsoleLogger.cs new file mode 100644 index 0000000..151d1e5 --- /dev/null +++ b/ArdalisRating/ConsoleLogger.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.IO; + +namespace ArdalisRating +{ + public class ConsoleLogger + { + public void Log(string message) + { + Console.WriteLine(message); + } + } +} diff --git a/ArdalisRating/FilePolicySource.cs b/ArdalisRating/FilePolicySource.cs new file mode 100644 index 0000000..9b1abd8 --- /dev/null +++ b/ArdalisRating/FilePolicySource.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.IO; + +namespace ArdalisRating +{ + public class FilePolicySource + { + public string GetPolicyFromSource() + { + return File.ReadAllText("policy.json"); + } + } +} diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index 0e373d3..6ee78ea 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -1,37 +1,45 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System; -using System.IO; namespace ArdalisRating { + public class JsonPolicySerializer + { + public Policy GetPolicyFromJsonString(string jsonString) + { + return JsonConvert.DeserializeObject(jsonString, + new StringEnumConverter()); + } + } /// /// The RatingEngine reads the policy application details from a file and produces a numeric /// rating value based on the details. /// public class RatingEngine { + public ConsoleLogger Logger { get; set; } = new ConsoleLogger(); + public FilePolicySource PolicySource { get; set; } = new FilePolicySource(); + public JsonPolicySerializer PolicySerializer { get; set; } = new JsonPolicySerializer(); public decimal Rating { get; set; } public void Rate() { - Console.WriteLine("Starting rate."); + Logger.Log("Starting rate."); - Console.WriteLine("Loading policy."); + Logger.Log("Loading policy."); - // load policy - open file policy.json - string policyJson = File.ReadAllText("policy.json"); + string policyJson = PolicySource.GetPolicyFromSource(); - var policy = JsonConvert.DeserializeObject(policyJson, - new StringEnumConverter()); + var policy = PolicySerializer.GetPolicyFromJsonString(policyJson); switch (policy.Type) { case PolicyType.Auto: - Console.WriteLine("Rating AUTO policy..."); - Console.WriteLine("Validating policy."); + Logger.Log("Rating AUTO policy..."); + Logger.Log("Validating policy."); if (String.IsNullOrEmpty(policy.Make)) { - Console.WriteLine("Auto policy must specify Make"); + Logger.Log("Auto policy must specify Make"); return; } if (policy.Make == "BMW") @@ -45,37 +53,37 @@ public void Rate() break; case PolicyType.Land: - Console.WriteLine("Rating LAND policy..."); - Console.WriteLine("Validating policy."); + Logger.Log("Rating LAND policy..."); + Logger.Log("Validating policy."); if (policy.BondAmount == 0 || policy.Valuation == 0) { - Console.WriteLine("Land policy must specify Bond Amount and Valuation."); + Logger.Log("Land policy must specify Bond Amount and Valuation."); return; } if (policy.BondAmount < 0.8m * policy.Valuation) { - Console.WriteLine("Insufficient bond amount."); + Logger.Log("Insufficient bond amount."); return; } Rating = policy.BondAmount * 0.05m; break; case PolicyType.Life: - Console.WriteLine("Rating LIFE policy..."); - Console.WriteLine("Validating policy."); + Logger.Log("Rating LIFE policy..."); + Logger.Log("Validating policy."); if (policy.DateOfBirth == DateTime.MinValue) { - Console.WriteLine("Life policy must include Date of Birth."); + Logger.Log("Life policy must include Date of Birth."); return; } if (policy.DateOfBirth < DateTime.Today.AddYears(-100)) { - Console.WriteLine("Centenarians are not eligible for coverage."); + Logger.Log("Centenarians are not eligible for coverage."); return; } if (policy.Amount == 0) { - Console.WriteLine("Life policy must include an Amount."); + Logger.Log("Life policy must include an Amount."); return; } int age = DateTime.Today.Year - policy.DateOfBirth.Year; @@ -95,11 +103,11 @@ public void Rate() break; default: - Console.WriteLine("Unknown policy type"); + Logger.Log("Unknown policy type"); break; } - Console.WriteLine("Rating completed."); + Logger.Log("Rating completed."); } } } From f073d7dd67452f39a0bbbf8af84e92428f8f5bf6 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Mon, 11 Feb 2019 09:28:16 -0500 Subject: [PATCH 04/16] Moved class to separate file --- ArdalisRating/JsonPolicySerializer.cs | 14 ++++++++++++++ ArdalisRating/RatingEngine.cs | 12 +----------- 2 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 ArdalisRating/JsonPolicySerializer.cs diff --git a/ArdalisRating/JsonPolicySerializer.cs b/ArdalisRating/JsonPolicySerializer.cs new file mode 100644 index 0000000..b068d75 --- /dev/null +++ b/ArdalisRating/JsonPolicySerializer.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace ArdalisRating +{ + public class JsonPolicySerializer + { + public Policy GetPolicyFromJsonString(string jsonString) + { + return JsonConvert.DeserializeObject(jsonString, + new StringEnumConverter()); + } + } +} diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index 6ee78ea..0cf5ac6 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -1,17 +1,7 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using System; +using System; namespace ArdalisRating { - public class JsonPolicySerializer - { - public Policy GetPolicyFromJsonString(string jsonString) - { - return JsonConvert.DeserializeObject(jsonString, - new StringEnumConverter()); - } - } /// /// The RatingEngine reads the policy application details from a file and produces a numeric /// rating value based on the details. From b465eac5d664963ec61f585189d868a9e05388cf Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Mon, 11 Feb 2019 10:13:58 -0500 Subject: [PATCH 05/16] Adding tests for JsonPolicySerializer --- ...PolicySerializerGetPolicyFromJsonString.cs | 52 +++++++++++++++++++ ArdalisRating/ConsoleLogger.cs | 5 +- ArdalisRating/FilePolicySource.cs | 5 +- 3 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs diff --git a/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs new file mode 100644 index 0000000..2ce2960 --- /dev/null +++ b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs @@ -0,0 +1,52 @@ +using Xunit; + +namespace ArdalisRating.Tests +{ + public class JsonPolicySerializerGetPolicyFromJsonString + { + [Fact] + public void ReturnsDefaultPolicyFromEmptyJsonString() + { + var inputJson = "{}"; + var serializer = new JsonPolicySerializer(); + + var result = serializer.GetPolicyFromJsonString(inputJson); + + var policy = new Policy(); + AssertPoliciesEqual(result, policy); + } + + [Fact] + public void ReturnsSimpleAutoPolicyFromValidJsonString() + { + var inputJson = @"{ + ""type"": ""Auto"", + ""make"": ""BMW"" +} +"; + var serializer = new JsonPolicySerializer(); + + var result = serializer.GetPolicyFromJsonString(inputJson); + + var policy = new Policy { Type = PolicyType.Auto, Make = "BMW" }; + AssertPoliciesEqual(result, policy); + } + + private static void AssertPoliciesEqual(Policy result, Policy policy) + { + Assert.Equal(policy.Address, result.Address); + Assert.Equal(policy.Amount, result.Amount); + Assert.Equal(policy.BondAmount, result.BondAmount); + Assert.Equal(policy.DateOfBirth, result.DateOfBirth); + Assert.Equal(policy.Deductible, result.Deductible); + Assert.Equal(policy.FullName, result.FullName); + Assert.Equal(policy.IsSmoker, result.IsSmoker); + Assert.Equal(policy.Make, result.Make); + Assert.Equal(policy.Miles, result.Miles); + Assert.Equal(policy.Model, result.Model); + Assert.Equal(policy.Type, result.Type); + Assert.Equal(policy.Valuation, result.Valuation); + Assert.Equal(policy.Year, result.Year); + } + } +} diff --git a/ArdalisRating/ConsoleLogger.cs b/ArdalisRating/ConsoleLogger.cs index 151d1e5..ecfafa0 100644 --- a/ArdalisRating/ConsoleLogger.cs +++ b/ArdalisRating/ConsoleLogger.cs @@ -1,7 +1,4 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using System; -using System.IO; +using System; namespace ArdalisRating { diff --git a/ArdalisRating/FilePolicySource.cs b/ArdalisRating/FilePolicySource.cs index 9b1abd8..a0ff64f 100644 --- a/ArdalisRating/FilePolicySource.cs +++ b/ArdalisRating/FilePolicySource.cs @@ -1,7 +1,4 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using System; -using System.IO; +using System.IO; namespace ArdalisRating { From 3587447a24bd6dde2769316a2b023cd68bb9ec31 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 17 Feb 2019 12:36:38 -0500 Subject: [PATCH 06/16] Code samples for OCP. --- ArdalisRating/RatingEngine.cs | 61 +++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index 0cf5ac6..f82bc62 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -100,4 +100,65 @@ public void Rate() Logger.Log("Rating completed."); } } + + public class DoAnything + { + private Func _function; + public DoAnything(Func function) + { + this._function = function; + } + public TResult Execute(TArg a) + { + return _function(a); + } + } + + public abstract class DoAnything2 + { + public abstract TResult Execute(TArg a); + } + public class MessageService + { + public string GetMessage() => "New message"; + } +public interface INotificationService +{ + void SendText(string SmsNumber, string message); + void SendEmail(string to, string from, string subject, string body); +} +public class SmtpNotificationService : INotificationService +{ + public void SendEmail(string to, string from, string subject, string body) + { + // actually send email here + } + + public void SendText(string SmsNumber, string message) + { + throw new NotImplementedException(); + } +} + public class DoOneThing +{ + private readonly MessageService _messageService; + + public DoOneThing(MessageService messageService) => _messageService = messageService; + public void Execute() + { + Console.WriteLine(_messageService.GetMessage()); + } +} + +public class DoSomethingElse +{ + public void SomethingElse() + { + var doThing = new DoOneThing(); + doThing.Execute(); + + // other stuff + } +} + } From b502eb60919c52495eca82de325cc564f24e1b74 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 23 Feb 2019 17:10:28 -0500 Subject: [PATCH 07/16] Create separate Rater classes --- ArdalisRating/AutoPolicyRater.cs | 35 +++++++++ ArdalisRating/LandPolicyRater.cs | 32 ++++++++ ArdalisRating/LifePolicyRater.cs | 50 ++++++++++++ ArdalisRating/RatingEngine.cs | 126 ++----------------------------- 4 files changed, 123 insertions(+), 120 deletions(-) create mode 100644 ArdalisRating/AutoPolicyRater.cs create mode 100644 ArdalisRating/LandPolicyRater.cs create mode 100644 ArdalisRating/LifePolicyRater.cs diff --git a/ArdalisRating/AutoPolicyRater.cs b/ArdalisRating/AutoPolicyRater.cs new file mode 100644 index 0000000..08525ca --- /dev/null +++ b/ArdalisRating/AutoPolicyRater.cs @@ -0,0 +1,35 @@ +using System; + +namespace ArdalisRating +{ + public class AutoPolicyRater + { + private readonly RatingEngine _engine; + private ConsoleLogger _logger; + + public AutoPolicyRater(RatingEngine engine, ConsoleLogger logger) + { + _engine = engine; + _logger = logger; + } + public void Rate(Policy policy) + { + _logger.Log("Rating AUTO policy..."); + _logger.Log("Validating policy."); + if (String.IsNullOrEmpty(policy.Make)) + { + _logger.Log("Auto policy must specify Make"); + return; + } + if (policy.Make == "BMW") + { + if (policy.Deductible < 500) + { + _engine.Rating = 1000m; + } + _engine.Rating = 900m; + } + + } + } +} diff --git a/ArdalisRating/LandPolicyRater.cs b/ArdalisRating/LandPolicyRater.cs new file mode 100644 index 0000000..3e22f4f --- /dev/null +++ b/ArdalisRating/LandPolicyRater.cs @@ -0,0 +1,32 @@ +using System; + +namespace ArdalisRating +{ + public class LandPolicyRater + { + private readonly RatingEngine _engine; + private ConsoleLogger _logger; + + public LandPolicyRater(RatingEngine engine, ConsoleLogger logger) + { + _engine = engine; + _logger = logger; + } + public void Rate(Policy policy) + { + _logger.Log("Rating LAND policy..."); + _logger.Log("Validating policy."); + if (policy.BondAmount == 0 || policy.Valuation == 0) + { + _logger.Log("Land policy must specify Bond Amount and Valuation."); + return; + } + if (policy.BondAmount < 0.8m * policy.Valuation) + { + _logger.Log("Insufficient bond amount."); + return; + } + _engine.Rating = policy.BondAmount * 0.05m; + } + } +} diff --git a/ArdalisRating/LifePolicyRater.cs b/ArdalisRating/LifePolicyRater.cs new file mode 100644 index 0000000..88621bb --- /dev/null +++ b/ArdalisRating/LifePolicyRater.cs @@ -0,0 +1,50 @@ +using System; + +namespace ArdalisRating +{ + public class LifePolicyRater + { + private readonly RatingEngine _engine; + private ConsoleLogger _logger; + + public LifePolicyRater(RatingEngine engine, ConsoleLogger logger) + { + _engine = engine; + _logger = logger; + } + public void Rate(Policy policy) + { + _logger.Log("Rating LIFE policy..."); + _logger.Log("Validating policy."); + if (policy.DateOfBirth == DateTime.MinValue) + { + _logger.Log("Life policy must include Date of Birth."); + return; + } + if (policy.DateOfBirth < DateTime.Today.AddYears(-100)) + { + _logger.Log("Centenarians are not eligible for coverage."); + return; + } + if (policy.Amount == 0) + { + _logger.Log("Life policy must include an Amount."); + return; + } + int age = DateTime.Today.Year - policy.DateOfBirth.Year; + if (policy.DateOfBirth.Month == DateTime.Today.Month && + DateTime.Today.Day < policy.DateOfBirth.Day || + DateTime.Today.Month < policy.DateOfBirth.Month) + { + age--; + } + decimal baseRate = policy.Amount * age / 200; + if (policy.IsSmoker) + { + _engine.Rating = baseRate * 2; + return; + } + _engine.Rating = baseRate; + } + } +} diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index f82bc62..6eeba4a 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -25,71 +25,18 @@ public void Rate() switch (policy.Type) { case PolicyType.Auto: - Logger.Log("Rating AUTO policy..."); - Logger.Log("Validating policy."); - if (String.IsNullOrEmpty(policy.Make)) - { - Logger.Log("Auto policy must specify Make"); - return; - } - if (policy.Make == "BMW") - { - if (policy.Deductible < 500) - { - Rating = 1000m; - } - Rating = 900m; - } + var rater = new AutoPolicyRater(this, this.Logger); + rater.Rate(policy); break; case PolicyType.Land: - Logger.Log("Rating LAND policy..."); - Logger.Log("Validating policy."); - if (policy.BondAmount == 0 || policy.Valuation == 0) - { - Logger.Log("Land policy must specify Bond Amount and Valuation."); - return; - } - if (policy.BondAmount < 0.8m * policy.Valuation) - { - Logger.Log("Insufficient bond amount."); - return; - } - Rating = policy.BondAmount * 0.05m; + var rater2 = new LandPolicyRater(this, this.Logger); + rater2.Rate(policy); break; case PolicyType.Life: - Logger.Log("Rating LIFE policy..."); - Logger.Log("Validating policy."); - if (policy.DateOfBirth == DateTime.MinValue) - { - Logger.Log("Life policy must include Date of Birth."); - return; - } - if (policy.DateOfBirth < DateTime.Today.AddYears(-100)) - { - Logger.Log("Centenarians are not eligible for coverage."); - return; - } - if (policy.Amount == 0) - { - Logger.Log("Life policy must include an Amount."); - return; - } - int age = DateTime.Today.Year - policy.DateOfBirth.Year; - if (policy.DateOfBirth.Month == DateTime.Today.Month && - DateTime.Today.Day < policy.DateOfBirth.Day || - DateTime.Today.Month < policy.DateOfBirth.Month) - { - age--; - } - decimal baseRate = policy.Amount * age / 200; - if (policy.IsSmoker) - { - Rating = baseRate * 2; - break; - } - Rating = baseRate; + var rater3 = new LifePolicyRater(this, this.Logger); + rater3.Rate(policy); break; default: @@ -100,65 +47,4 @@ public void Rate() Logger.Log("Rating completed."); } } - - public class DoAnything - { - private Func _function; - public DoAnything(Func function) - { - this._function = function; - } - public TResult Execute(TArg a) - { - return _function(a); - } - } - - public abstract class DoAnything2 - { - public abstract TResult Execute(TArg a); - } - public class MessageService - { - public string GetMessage() => "New message"; - } -public interface INotificationService -{ - void SendText(string SmsNumber, string message); - void SendEmail(string to, string from, string subject, string body); -} -public class SmtpNotificationService : INotificationService -{ - public void SendEmail(string to, string from, string subject, string body) - { - // actually send email here - } - - public void SendText(string SmsNumber, string message) - { - throw new NotImplementedException(); - } -} - public class DoOneThing -{ - private readonly MessageService _messageService; - - public DoOneThing(MessageService messageService) => _messageService = messageService; - public void Execute() - { - Console.WriteLine(_messageService.GetMessage()); - } -} - -public class DoSomethingElse -{ - public void SomethingElse() - { - var doThing = new DoOneThing(); - doThing.Execute(); - - // other stuff - } -} - } From 8219c4c0594a19c3255d6ef1d329c6d2c815234d Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 23 Feb 2019 17:18:13 -0500 Subject: [PATCH 08/16] Implement Rater Factory and base class --- ArdalisRating/AutoPolicyRater.cs | 22 ++++++++++++++++------ ArdalisRating/LandPolicyRater.cs | 15 +++++---------- ArdalisRating/LifePolicyRater.cs | 11 ++++------- ArdalisRating/RaterFactory.cs | 25 +++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 ArdalisRating/RaterFactory.cs diff --git a/ArdalisRating/AutoPolicyRater.cs b/ArdalisRating/AutoPolicyRater.cs index 08525ca..31c28ce 100644 --- a/ArdalisRating/AutoPolicyRater.cs +++ b/ArdalisRating/AutoPolicyRater.cs @@ -2,17 +2,28 @@ namespace ArdalisRating { - public class AutoPolicyRater + public abstract class Rater { - private readonly RatingEngine _engine; - private ConsoleLogger _logger; + protected readonly RatingEngine _engine; + protected readonly ConsoleLogger _logger; - public AutoPolicyRater(RatingEngine engine, ConsoleLogger logger) + public Rater(RatingEngine engine, ConsoleLogger logger) { _engine = engine; _logger = logger; } - public void Rate(Policy policy) + + public abstract void Rate(Policy policy); + } + + public class AutoPolicyRater : Rater + { + public AutoPolicyRater(RatingEngine engine, ConsoleLogger logger) + : base(engine, logger) + { + } + + public override void Rate(Policy policy) { _logger.Log("Rating AUTO policy..."); _logger.Log("Validating policy."); @@ -29,7 +40,6 @@ public void Rate(Policy policy) } _engine.Rating = 900m; } - } } } diff --git a/ArdalisRating/LandPolicyRater.cs b/ArdalisRating/LandPolicyRater.cs index 3e22f4f..e42fc26 100644 --- a/ArdalisRating/LandPolicyRater.cs +++ b/ArdalisRating/LandPolicyRater.cs @@ -1,18 +1,13 @@ -using System; - -namespace ArdalisRating +namespace ArdalisRating { - public class LandPolicyRater + public class LandPolicyRater : Rater { - private readonly RatingEngine _engine; - private ConsoleLogger _logger; - public LandPolicyRater(RatingEngine engine, ConsoleLogger logger) + :base(engine,logger) { - _engine = engine; - _logger = logger; } - public void Rate(Policy policy) + + public override void Rate(Policy policy) { _logger.Log("Rating LAND policy..."); _logger.Log("Validating policy."); diff --git a/ArdalisRating/LifePolicyRater.cs b/ArdalisRating/LifePolicyRater.cs index 88621bb..fe07a9c 100644 --- a/ArdalisRating/LifePolicyRater.cs +++ b/ArdalisRating/LifePolicyRater.cs @@ -2,17 +2,14 @@ namespace ArdalisRating { - public class LifePolicyRater + public class LifePolicyRater : Rater { - private readonly RatingEngine _engine; - private ConsoleLogger _logger; - public LifePolicyRater(RatingEngine engine, ConsoleLogger logger) + : base(engine, logger) { - _engine = engine; - _logger = logger; } - public void Rate(Policy policy) + + public override void Rate(Policy policy) { _logger.Log("Rating LIFE policy..."); _logger.Log("Validating policy."); diff --git a/ArdalisRating/RaterFactory.cs b/ArdalisRating/RaterFactory.cs new file mode 100644 index 0000000..f5858d4 --- /dev/null +++ b/ArdalisRating/RaterFactory.cs @@ -0,0 +1,25 @@ +namespace ArdalisRating +{ + public class RaterFactory + { + public Rater Create(Policy policy, RatingEngine engine) + { + switch (policy.Type) + { + case PolicyType.Auto: + return new AutoPolicyRater(engine, engine.Logger); + + case PolicyType.Land: + return new LandPolicyRater(engine, engine.Logger); + + case PolicyType.Life: + return new LifePolicyRater(engine, engine.Logger); + + default: + // TODO: Implement Null Object Pattern + // Logger.Log("Unknown policy type"); + return null; + } + } + } +} From edb2ea8165c24f8bae3f58728ecfebb1d3c6e98d Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 23 Feb 2019 17:21:15 -0500 Subject: [PATCH 09/16] Implement UnknownPolicyRater --- ArdalisRating/RaterFactory.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/ArdalisRating/RaterFactory.cs b/ArdalisRating/RaterFactory.cs index f5858d4..f7beb07 100644 --- a/ArdalisRating/RaterFactory.cs +++ b/ArdalisRating/RaterFactory.cs @@ -16,10 +16,21 @@ public Rater Create(Policy policy, RatingEngine engine) return new LifePolicyRater(engine, engine.Logger); default: - // TODO: Implement Null Object Pattern - // Logger.Log("Unknown policy type"); - return null; + return new UnknownPolicyRater(engine, engine.Logger); } } } + + public class UnknownPolicyRater : Rater + { + public UnknownPolicyRater(RatingEngine engine, ConsoleLogger logger) + : base(engine, logger) + { + } + + public override void Rate(Policy policy) + { + _logger.Log("Unknown policy type"); + } + } } From 23a2ac1d893e58278897ba56f1011f8c19f6dce8 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 23 Feb 2019 17:24:43 -0500 Subject: [PATCH 10/16] Moved types to files and wired up factory --- ArdalisRating/AutoPolicyRater.cs | 14 -------------- ArdalisRating/Rater.cs | 16 ++++++++++++++++ ArdalisRating/RaterFactory.cs | 13 ------------- ArdalisRating/RatingEngine.cs | 23 +++-------------------- ArdalisRating/UnknownPolicyRater.cs | 15 +++++++++++++++ 5 files changed, 34 insertions(+), 47 deletions(-) create mode 100644 ArdalisRating/Rater.cs create mode 100644 ArdalisRating/UnknownPolicyRater.cs diff --git a/ArdalisRating/AutoPolicyRater.cs b/ArdalisRating/AutoPolicyRater.cs index 31c28ce..10a134a 100644 --- a/ArdalisRating/AutoPolicyRater.cs +++ b/ArdalisRating/AutoPolicyRater.cs @@ -2,20 +2,6 @@ namespace ArdalisRating { - public abstract class Rater - { - protected readonly RatingEngine _engine; - protected readonly ConsoleLogger _logger; - - public Rater(RatingEngine engine, ConsoleLogger logger) - { - _engine = engine; - _logger = logger; - } - - public abstract void Rate(Policy policy); - } - public class AutoPolicyRater : Rater { public AutoPolicyRater(RatingEngine engine, ConsoleLogger logger) diff --git a/ArdalisRating/Rater.cs b/ArdalisRating/Rater.cs new file mode 100644 index 0000000..641de6b --- /dev/null +++ b/ArdalisRating/Rater.cs @@ -0,0 +1,16 @@ +namespace ArdalisRating +{ + public abstract class Rater + { + protected readonly RatingEngine _engine; + protected readonly ConsoleLogger _logger; + + public Rater(RatingEngine engine, ConsoleLogger logger) + { + _engine = engine; + _logger = logger; + } + + public abstract void Rate(Policy policy); + } +} diff --git a/ArdalisRating/RaterFactory.cs b/ArdalisRating/RaterFactory.cs index f7beb07..ad62f54 100644 --- a/ArdalisRating/RaterFactory.cs +++ b/ArdalisRating/RaterFactory.cs @@ -20,17 +20,4 @@ public Rater Create(Policy policy, RatingEngine engine) } } } - - public class UnknownPolicyRater : Rater - { - public UnknownPolicyRater(RatingEngine engine, ConsoleLogger logger) - : base(engine, logger) - { - } - - public override void Rate(Policy policy) - { - _logger.Log("Unknown policy type"); - } - } } diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index 6eeba4a..782ecb7 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -22,27 +22,10 @@ public void Rate() var policy = PolicySerializer.GetPolicyFromJsonString(policyJson); - switch (policy.Type) - { - case PolicyType.Auto: - var rater = new AutoPolicyRater(this, this.Logger); - rater.Rate(policy); - break; + var factory = new RaterFactory(); - case PolicyType.Land: - var rater2 = new LandPolicyRater(this, this.Logger); - rater2.Rate(policy); - break; - - case PolicyType.Life: - var rater3 = new LifePolicyRater(this, this.Logger); - rater3.Rate(policy); - break; - - default: - Logger.Log("Unknown policy type"); - break; - } + var rater = factory.Create(policy, this); + rater.Rate(policy); Logger.Log("Rating completed."); } diff --git a/ArdalisRating/UnknownPolicyRater.cs b/ArdalisRating/UnknownPolicyRater.cs new file mode 100644 index 0000000..2068fb0 --- /dev/null +++ b/ArdalisRating/UnknownPolicyRater.cs @@ -0,0 +1,15 @@ +namespace ArdalisRating +{ + public class UnknownPolicyRater : Rater + { + public UnknownPolicyRater(RatingEngine engine, ConsoleLogger logger) + : base(engine, logger) + { + } + + public override void Rate(Policy policy) + { + _logger.Log("Unknown policy type"); + } + } +} From cd7c1b8ba5009b7f64b45707029843f28d122cef Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 23 Feb 2019 17:37:59 -0500 Subject: [PATCH 11/16] Implemented Flood Policy Rater --- ArdalisRating/FloodPolicyRater.cs | 43 +++++++++++++++++++++++++++++++ ArdalisRating/Policy.cs | 5 +++- ArdalisRating/PolicyType.cs | 3 ++- ArdalisRating/RaterFactory.cs | 4 +++ ArdalisRating/policy.json | 5 ++-- 5 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 ArdalisRating/FloodPolicyRater.cs diff --git a/ArdalisRating/FloodPolicyRater.cs b/ArdalisRating/FloodPolicyRater.cs new file mode 100644 index 0000000..ff6508b --- /dev/null +++ b/ArdalisRating/FloodPolicyRater.cs @@ -0,0 +1,43 @@ +namespace ArdalisRating +{ + public class FloodPolicyRater : Rater + { + public FloodPolicyRater(RatingEngine engine, ConsoleLogger logger) + : base(engine, logger) + { + } + + public override void Rate(Policy policy) + { + _logger.Log("Rating FLOOD policy..."); + _logger.Log("Validating policy."); + if (policy.BondAmount == 0 || policy.Valuation == 0) + { + _logger.Log("Flood policy must specify Bond Amount and Valuation."); + return; + } + if (policy.ElevationAboveSeaLevelFeet <= 0) + { + _logger.Log("Flood policy is not available for elevations at or below sea level."); + return; + } + if (policy.BondAmount < 0.8m * policy.Valuation) + { + _logger.Log("Insufficient bond amount."); + return; + } + decimal multiple = 1.0m; + if(policy.ElevationAboveSeaLevelFeet < 100) + { + multiple = 2.0m; + } else if (policy.ElevationAboveSeaLevelFeet < 500) + { + multiple = 1.5m; + } else if (policy.ElevationAboveSeaLevelFeet < 1000) + { + multiple = 1.1m; + } + _engine.Rating = policy.BondAmount * 0.05m * multiple; + } + } +} diff --git a/ArdalisRating/Policy.cs b/ArdalisRating/Policy.cs index 791432d..5b080e4 100644 --- a/ArdalisRating/Policy.cs +++ b/ArdalisRating/Policy.cs @@ -20,6 +20,10 @@ public class Policy public decimal BondAmount { get; set; } #endregion + #region Flood In Addition To Land + public int ElevationAboveSeaLevelFeet { get; set; } + #endregion + #region Auto public string Make { get; set; } public string Model { get; set; } @@ -27,6 +31,5 @@ public class Policy public int Miles { get; set; } public decimal Deductible { get; set; } #endregion - } } diff --git a/ArdalisRating/PolicyType.cs b/ArdalisRating/PolicyType.cs index 741c630..d391e03 100644 --- a/ArdalisRating/PolicyType.cs +++ b/ArdalisRating/PolicyType.cs @@ -7,6 +7,7 @@ public enum PolicyType { Life = 0, Land = 1, - Auto = 2 + Auto = 2, + Flood = 3 } } diff --git a/ArdalisRating/RaterFactory.cs b/ArdalisRating/RaterFactory.cs index ad62f54..2a6394e 100644 --- a/ArdalisRating/RaterFactory.cs +++ b/ArdalisRating/RaterFactory.cs @@ -9,6 +9,9 @@ public Rater Create(Policy policy, RatingEngine engine) case PolicyType.Auto: return new AutoPolicyRater(engine, engine.Logger); + case PolicyType.Flood: + return new FloodPolicyRater(engine, engine.Logger); + case PolicyType.Land: return new LandPolicyRater(engine, engine.Logger); @@ -16,6 +19,7 @@ public Rater Create(Policy policy, RatingEngine engine) return new LifePolicyRater(engine, engine.Logger); default: + // currently this can't be reached return new UnknownPolicyRater(engine, engine.Logger); } } diff --git a/ArdalisRating/policy.json b/ArdalisRating/policy.json index c138e8b..a02f104 100644 --- a/ArdalisRating/policy.json +++ b/ArdalisRating/policy.json @@ -1,5 +1,6 @@ { - "type": "Land", + "type": "Flood", "bondAmount": "1000000", - "valuation": "1100000" + "valuation": "1100000", + "elevationAboveSeaLevelFeet": "1001" } From 8dd5dccd43adcd383a64a619d5d4ae8ffc893155 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sat, 23 Feb 2019 17:47:42 -0500 Subject: [PATCH 12/16] Demo using reflection Some tests are broken. --- ...PolicySerializerGetPolicyFromJsonString.cs | 4 ++- ArdalisRating.Tests/RatingEngineRate.cs | 4 +-- ArdalisRating/Policy.cs | 3 +- ArdalisRating/RaterFactory.cs | 28 ++++++++----------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs index 2ce2960..1177285 100644 --- a/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs +++ b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs @@ -28,7 +28,9 @@ public void ReturnsSimpleAutoPolicyFromValidJsonString() var result = serializer.GetPolicyFromJsonString(inputJson); - var policy = new Policy { Type = PolicyType.Auto, Make = "BMW" }; + var policy = new Policy { + //Type = PolicyType.Auto, + Make = "BMW" }; AssertPoliciesEqual(result, policy); } diff --git a/ArdalisRating.Tests/RatingEngineRate.cs b/ArdalisRating.Tests/RatingEngineRate.cs index b470f06..08a515a 100644 --- a/ArdalisRating.Tests/RatingEngineRate.cs +++ b/ArdalisRating.Tests/RatingEngineRate.cs @@ -12,7 +12,7 @@ public void ReturnsRatingOf10000For200000LandPolicy() { var policy = new Policy { - Type = PolicyType.Land, + //Type = PolicyType.Land, BondAmount = 200000, Valuation = 200000 }; @@ -31,7 +31,7 @@ public void ReturnsRatingOf0For200000BondOn260000LandPolicy() { var policy = new Policy { - Type = PolicyType.Land, + //Type = PolicyType.Land, BondAmount = 200000, Valuation = 260000 }; diff --git a/ArdalisRating/Policy.cs b/ArdalisRating/Policy.cs index 5b080e4..522fc48 100644 --- a/ArdalisRating/Policy.cs +++ b/ArdalisRating/Policy.cs @@ -5,7 +5,8 @@ namespace ArdalisRating public class Policy { - public PolicyType Type { get; set; } + public string Type { get; set; } + #region Life Insurance public string FullName { get; set; } public DateTime DateOfBirth { get; set; } diff --git a/ArdalisRating/RaterFactory.cs b/ArdalisRating/RaterFactory.cs index 2a6394e..2a90dc2 100644 --- a/ArdalisRating/RaterFactory.cs +++ b/ArdalisRating/RaterFactory.cs @@ -1,26 +1,20 @@ -namespace ArdalisRating +using System; + +namespace ArdalisRating { public class RaterFactory { public Rater Create(Policy policy, RatingEngine engine) { - switch (policy.Type) + try { - case PolicyType.Auto: - return new AutoPolicyRater(engine, engine.Logger); - - case PolicyType.Flood: - return new FloodPolicyRater(engine, engine.Logger); - - case PolicyType.Land: - return new LandPolicyRater(engine, engine.Logger); - - case PolicyType.Life: - return new LifePolicyRater(engine, engine.Logger); - - default: - // currently this can't be reached - return new UnknownPolicyRater(engine, engine.Logger); + return (Rater)Activator.CreateInstance( + Type.GetType($"ArdalisRating.{policy.Type}PolicyRater"), + new object[] { engine, engine.Logger }); + } + catch + { + return new UnknownPolicyRater(engine, engine.Logger); } } } From f68ac81b55bc34714229ba36055a2b3872ca96f4 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 24 Feb 2019 10:37:48 -0500 Subject: [PATCH 13/16] Modifying to use nulls for now --- ArdalisRating/RaterFactory.cs | 2 +- ArdalisRating/RatingEngine.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ArdalisRating/RaterFactory.cs b/ArdalisRating/RaterFactory.cs index 2a90dc2..6cfc990 100644 --- a/ArdalisRating/RaterFactory.cs +++ b/ArdalisRating/RaterFactory.cs @@ -14,7 +14,7 @@ public Rater Create(Policy policy, RatingEngine engine) } catch { - return new UnknownPolicyRater(engine, engine.Logger); + return null; } } } diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index 782ecb7..9ce7f5e 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -25,7 +25,7 @@ public void Rate() var factory = new RaterFactory(); var rater = factory.Create(policy, this); - rater.Rate(policy); + rater?.Rate(policy); Logger.Log("Rating completed."); } From fcbca655feda39b5ca5c7e44781671c6e3501ccd Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 24 Feb 2019 14:06:03 -0500 Subject: [PATCH 14/16] Implementing Null Object Pattern to achieve LSP. --- ArdalisRating/RaterFactory.cs | 2 +- ArdalisRating/RatingEngine.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ArdalisRating/RaterFactory.cs b/ArdalisRating/RaterFactory.cs index 6cfc990..2a90dc2 100644 --- a/ArdalisRating/RaterFactory.cs +++ b/ArdalisRating/RaterFactory.cs @@ -14,7 +14,7 @@ public Rater Create(Policy policy, RatingEngine engine) } catch { - return null; + return new UnknownPolicyRater(engine, engine.Logger); } } } diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index 9ce7f5e..782ecb7 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -25,7 +25,7 @@ public void Rate() var factory = new RaterFactory(); var rater = factory.Create(policy, this); - rater?.Rate(policy); + rater.Rate(policy); Logger.Log("Rating completed."); } From 7015223b87e95fb9f9215531f31314782377ca48 Mon Sep 17 00:00:00 2001 From: Steve Smith Date: Sun, 24 Feb 2019 17:37:49 -0500 Subject: [PATCH 15/16] Implementing IRatingContext Also fixing some tests that were broken previously. --- ...PolicySerializerGetPolicyFromJsonString.cs | 2 +- ArdalisRating.Tests/RatingEngineRate.cs | 32 ++++++------- ArdalisRating/AutoPolicyRater.cs | 8 ++-- ArdalisRating/DefaultRatingContext.cs | 46 +++++++++++++++++++ ArdalisRating/FloodPolicyRater.cs | 6 +-- ArdalisRating/IRatingContext.cs | 15 ++++++ ArdalisRating/LandPolicyRater.cs | 6 +-- ArdalisRating/LifePolicyRater.cs | 8 ++-- ArdalisRating/Rater.cs | 8 ++-- ArdalisRating/RaterFactory.cs | 6 +-- ArdalisRating/RatingEngine.cs | 25 +++++----- ArdalisRating/UnknownPolicyRater.cs | 4 +- 12 files changed, 113 insertions(+), 53 deletions(-) create mode 100644 ArdalisRating/DefaultRatingContext.cs create mode 100644 ArdalisRating/IRatingContext.cs diff --git a/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs index 1177285..53dbeba 100644 --- a/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs +++ b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs @@ -29,7 +29,7 @@ public void ReturnsSimpleAutoPolicyFromValidJsonString() var result = serializer.GetPolicyFromJsonString(inputJson); var policy = new Policy { - //Type = PolicyType.Auto, + Type = "Auto", Make = "BMW" }; AssertPoliciesEqual(result, policy); } diff --git a/ArdalisRating.Tests/RatingEngineRate.cs b/ArdalisRating.Tests/RatingEngineRate.cs index 08a515a..f470936 100644 --- a/ArdalisRating.Tests/RatingEngineRate.cs +++ b/ArdalisRating.Tests/RatingEngineRate.cs @@ -7,24 +7,24 @@ namespace ArdalisRating.Tests { public class RatingEngineRate { -[Fact] -public void ReturnsRatingOf10000For200000LandPolicy() -{ - var policy = new Policy - { - //Type = PolicyType.Land, - BondAmount = 200000, - Valuation = 200000 - }; - string json = JsonConvert.SerializeObject(policy); - File.WriteAllText("policy.json", json); + [Fact] + public void ReturnsRatingOf10000For200000LandPolicy() + { + var policy = new Policy + { + Type = "Land", + BondAmount = 200000, + Valuation = 200000 + }; + string json = JsonConvert.SerializeObject(policy); + File.WriteAllText("policy.json", json); - var engine = new RatingEngine(); - engine.Rate(); - var result = engine.Rating; + var engine = new RatingEngine(); + engine.Rate(); + var result = engine.Rating; - Assert.Equal(10000, result); -} + Assert.Equal(10000, result); + } [Fact] public void ReturnsRatingOf0For200000BondOn260000LandPolicy() diff --git a/ArdalisRating/AutoPolicyRater.cs b/ArdalisRating/AutoPolicyRater.cs index 10a134a..7b1cc52 100644 --- a/ArdalisRating/AutoPolicyRater.cs +++ b/ArdalisRating/AutoPolicyRater.cs @@ -4,8 +4,8 @@ namespace ArdalisRating { public class AutoPolicyRater : Rater { - public AutoPolicyRater(RatingEngine engine, ConsoleLogger logger) - : base(engine, logger) + public AutoPolicyRater(IRatingContext context) + : base(context) { } @@ -22,9 +22,9 @@ public override void Rate(Policy policy) { if (policy.Deductible < 500) { - _engine.Rating = 1000m; + _context.UpdateRating(1000m); } - _engine.Rating = 900m; + _context.UpdateRating(900m); } } } diff --git a/ArdalisRating/DefaultRatingContext.cs b/ArdalisRating/DefaultRatingContext.cs new file mode 100644 index 0000000..eaf8235 --- /dev/null +++ b/ArdalisRating/DefaultRatingContext.cs @@ -0,0 +1,46 @@ +using System; + +namespace ArdalisRating +{ + public class DefaultRatingContext : IRatingContext + { + public RatingEngine Engine { get; set; } + + public ConsoleLogger Logger => new ConsoleLogger(); + + public Rater CreateRaterForPolicy(Policy policy, IRatingContext context) + { + return new RaterFactory().Create(policy, context); + } + + public Policy GetPolicyFromJsonString(string policyJson) + { + return new JsonPolicySerializer().GetPolicyFromJsonString(policyJson); + } + + public Policy GetPolicyFromXmlString(string policyXml) + { + throw new NotImplementedException(); + } + + public string LoadPolicyFromFile() + { + return new FilePolicySource().GetPolicyFromSource(); + } + + public string LoadPolicyFromURI(string uri) + { + throw new NotImplementedException(); + } + + public void Log(string message) + { + new ConsoleLogger().Log(message); + } + + public void UpdateRating(decimal rating) + { + Engine.Rating = rating; + } + } +} diff --git a/ArdalisRating/FloodPolicyRater.cs b/ArdalisRating/FloodPolicyRater.cs index ff6508b..7b5c37b 100644 --- a/ArdalisRating/FloodPolicyRater.cs +++ b/ArdalisRating/FloodPolicyRater.cs @@ -2,8 +2,8 @@ { public class FloodPolicyRater : Rater { - public FloodPolicyRater(RatingEngine engine, ConsoleLogger logger) - : base(engine, logger) + public FloodPolicyRater(IRatingContext context) + : base(context) { } @@ -37,7 +37,7 @@ public override void Rate(Policy policy) { multiple = 1.1m; } - _engine.Rating = policy.BondAmount * 0.05m * multiple; + _context.UpdateRating(policy.BondAmount * 0.05m * multiple); } } } diff --git a/ArdalisRating/IRatingContext.cs b/ArdalisRating/IRatingContext.cs new file mode 100644 index 0000000..aab2602 --- /dev/null +++ b/ArdalisRating/IRatingContext.cs @@ -0,0 +1,15 @@ +namespace ArdalisRating +{ + public interface IRatingContext + { + void Log(string message); + string LoadPolicyFromFile(); + string LoadPolicyFromURI(string uri); + Policy GetPolicyFromJsonString(string policyJson); + Policy GetPolicyFromXmlString(string policyXml); + Rater CreateRaterForPolicy(Policy policy, IRatingContext context); + void UpdateRating(decimal rating); + RatingEngine Engine { get; set; } + ConsoleLogger Logger { get; } + } +} diff --git a/ArdalisRating/LandPolicyRater.cs b/ArdalisRating/LandPolicyRater.cs index e42fc26..b346831 100644 --- a/ArdalisRating/LandPolicyRater.cs +++ b/ArdalisRating/LandPolicyRater.cs @@ -2,8 +2,8 @@ { public class LandPolicyRater : Rater { - public LandPolicyRater(RatingEngine engine, ConsoleLogger logger) - :base(engine,logger) + public LandPolicyRater(IRatingContext context) + :base(context) { } @@ -21,7 +21,7 @@ public override void Rate(Policy policy) _logger.Log("Insufficient bond amount."); return; } - _engine.Rating = policy.BondAmount * 0.05m; + _context.UpdateRating(policy.BondAmount * 0.05m); } } } diff --git a/ArdalisRating/LifePolicyRater.cs b/ArdalisRating/LifePolicyRater.cs index fe07a9c..01b2e25 100644 --- a/ArdalisRating/LifePolicyRater.cs +++ b/ArdalisRating/LifePolicyRater.cs @@ -4,8 +4,8 @@ namespace ArdalisRating { public class LifePolicyRater : Rater { - public LifePolicyRater(RatingEngine engine, ConsoleLogger logger) - : base(engine, logger) + public LifePolicyRater(IRatingContext context) + : base(context) { } @@ -38,10 +38,10 @@ public override void Rate(Policy policy) decimal baseRate = policy.Amount * age / 200; if (policy.IsSmoker) { - _engine.Rating = baseRate * 2; + _context.UpdateRating(baseRate * 2); return; } - _engine.Rating = baseRate; + _context.UpdateRating(baseRate); } } } diff --git a/ArdalisRating/Rater.cs b/ArdalisRating/Rater.cs index 641de6b..1932f97 100644 --- a/ArdalisRating/Rater.cs +++ b/ArdalisRating/Rater.cs @@ -2,13 +2,13 @@ { public abstract class Rater { - protected readonly RatingEngine _engine; + protected readonly IRatingContext _context; protected readonly ConsoleLogger _logger; - public Rater(RatingEngine engine, ConsoleLogger logger) + public Rater(IRatingContext context) { - _engine = engine; - _logger = logger; + _context = context; + _logger = _context.Logger; } public abstract void Rate(Policy policy); diff --git a/ArdalisRating/RaterFactory.cs b/ArdalisRating/RaterFactory.cs index 2a90dc2..eed7828 100644 --- a/ArdalisRating/RaterFactory.cs +++ b/ArdalisRating/RaterFactory.cs @@ -4,17 +4,17 @@ namespace ArdalisRating { public class RaterFactory { - public Rater Create(Policy policy, RatingEngine engine) + public Rater Create(Policy policy, IRatingContext context) { try { return (Rater)Activator.CreateInstance( Type.GetType($"ArdalisRating.{policy.Type}PolicyRater"), - new object[] { engine, engine.Logger }); + new object[] { context }); } catch { - return new UnknownPolicyRater(engine, engine.Logger); + return new UnknownPolicyRater(context); } } } diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs index 782ecb7..9752592 100644 --- a/ArdalisRating/RatingEngine.cs +++ b/ArdalisRating/RatingEngine.cs @@ -1,6 +1,4 @@ -using System; - -namespace ArdalisRating +namespace ArdalisRating { /// /// The RatingEngine reads the policy application details from a file and produces a numeric @@ -8,26 +6,27 @@ namespace ArdalisRating /// public class RatingEngine { - public ConsoleLogger Logger { get; set; } = new ConsoleLogger(); - public FilePolicySource PolicySource { get; set; } = new FilePolicySource(); - public JsonPolicySerializer PolicySerializer { get; set; } = new JsonPolicySerializer(); + public IRatingContext Context { get; set; } = new DefaultRatingContext(); public decimal Rating { get; set; } + public RatingEngine() + { + Context.Engine = this; + } public void Rate() { - Logger.Log("Starting rate."); + Context.Log("Starting rate."); - Logger.Log("Loading policy."); + Context.Log("Loading policy."); - string policyJson = PolicySource.GetPolicyFromSource(); + string policyJson = Context.LoadPolicyFromFile(); - var policy = PolicySerializer.GetPolicyFromJsonString(policyJson); + var policy = Context.GetPolicyFromJsonString(policyJson); - var factory = new RaterFactory(); + var rater = Context.CreateRaterForPolicy(policy, Context); - var rater = factory.Create(policy, this); rater.Rate(policy); - Logger.Log("Rating completed."); + Context.Log("Rating completed."); } } } diff --git a/ArdalisRating/UnknownPolicyRater.cs b/ArdalisRating/UnknownPolicyRater.cs index 2068fb0..1b07919 100644 --- a/ArdalisRating/UnknownPolicyRater.cs +++ b/ArdalisRating/UnknownPolicyRater.cs @@ -2,8 +2,8 @@ { public class UnknownPolicyRater : Rater { - public UnknownPolicyRater(RatingEngine engine, ConsoleLogger logger) - : base(engine, logger) + public UnknownPolicyRater(IRatingContext context) + : base(context) { } From 6f4311df5d1ab41a4374f50fa12d48f594d4c2b5 Mon Sep 17 00:00:00 2001 From: varghesec Date: Wed, 12 Aug 2020 06:00:43 +0530 Subject: [PATCH 16/16] after DIP and organization of files --- .../ArdalisRating.Tests.csproj | 13 +-- ...PolicySerializerGetPolicyFromJsonString.cs | 17 ++-- ArdalisRating.Tests/RatingEngineRate.cs | 80 ++++++++++++++++--- ArdalisRating/ArdalisRating.csproj | 2 +- ArdalisRating/AutoPolicyRater.cs | 31 ------- ArdalisRating/Core/Interfaces/ILogger.cs | 8 ++ .../Core/Interfaces/IPolicySerializer.cs | 7 ++ .../Core/Interfaces/IPolicySource.cs | 7 ++ ArdalisRating/{ => Core/Model}/Policy.cs | 0 ArdalisRating/{ => Core/Model}/PolicyType.cs | 0 ArdalisRating/Core/Rater/AutoPolicyRater.cs | 43 ++++++++++ ArdalisRating/Core/Rater/FloodPolicyRater.cs | 54 +++++++++++++ ArdalisRating/Core/Rater/LandPolicyRater.cs | 36 +++++++++ .../{ => Core/Rater}/LifePolicyRater.cs | 29 +++---- ArdalisRating/Core/Rater/Rater.cs | 37 +++++++++ ArdalisRating/Core/Rater/RaterFactory.cs | 39 +++++++++ .../Core/Rater/UnknownPolicyRater.cs | 32 ++++++++ ArdalisRating/Core/RatingEngine.cs | 60 ++++++++++++++ ArdalisRating/DefaultRatingContext.cs | 25 ++++-- ArdalisRating/FloodPolicyRater.cs | 43 ---------- ArdalisRating/IRatingContext.cs | 9 ++- ArdalisRating/IRatingUpdater.cs | 7 ++ .../Loggers}/ConsoleLogger.cs | 2 +- .../Infrastructure/Loggers/FileLogger.cs | 16 ++++ .../PolicySources}/FilePolicySource.cs | 2 +- .../Serializers}/JsonPolicySerializer.cs | 2 +- ArdalisRating/LandPolicyRater.cs | 27 ------- ArdalisRating/Rater.cs | 16 ---- ArdalisRating/RaterFactory.cs | 21 ----- ArdalisRating/RatingEngine.cs | 32 -------- ArdalisRating/RatingUpdater.cs | 17 ++++ ArdalisRating/{ => UI}/Program.cs | 5 +- ArdalisRating/UnknownPolicyRater.cs | 15 ---- ArdalisRating/policy.json | 5 +- 34 files changed, 501 insertions(+), 238 deletions(-) delete mode 100644 ArdalisRating/AutoPolicyRater.cs create mode 100644 ArdalisRating/Core/Interfaces/ILogger.cs create mode 100644 ArdalisRating/Core/Interfaces/IPolicySerializer.cs create mode 100644 ArdalisRating/Core/Interfaces/IPolicySource.cs rename ArdalisRating/{ => Core/Model}/Policy.cs (100%) rename ArdalisRating/{ => Core/Model}/PolicyType.cs (100%) create mode 100644 ArdalisRating/Core/Rater/AutoPolicyRater.cs create mode 100644 ArdalisRating/Core/Rater/FloodPolicyRater.cs create mode 100644 ArdalisRating/Core/Rater/LandPolicyRater.cs rename ArdalisRating/{ => Core/Rater}/LifePolicyRater.cs (53%) create mode 100644 ArdalisRating/Core/Rater/Rater.cs create mode 100644 ArdalisRating/Core/Rater/RaterFactory.cs create mode 100644 ArdalisRating/Core/Rater/UnknownPolicyRater.cs create mode 100644 ArdalisRating/Core/RatingEngine.cs delete mode 100644 ArdalisRating/FloodPolicyRater.cs create mode 100644 ArdalisRating/IRatingUpdater.cs rename ArdalisRating/{ => Infrastructure/Loggers}/ConsoleLogger.cs (79%) create mode 100644 ArdalisRating/Infrastructure/Loggers/FileLogger.cs rename ArdalisRating/{ => Infrastructure/PolicySources}/FilePolicySource.cs (77%) rename ArdalisRating/{ => Infrastructure/Serializers}/JsonPolicySerializer.cs (83%) delete mode 100644 ArdalisRating/LandPolicyRater.cs delete mode 100644 ArdalisRating/Rater.cs delete mode 100644 ArdalisRating/RaterFactory.cs delete mode 100644 ArdalisRating/RatingEngine.cs create mode 100644 ArdalisRating/RatingUpdater.cs rename ArdalisRating/{ => UI}/Program.cs (65%) delete mode 100644 ArdalisRating/UnknownPolicyRater.cs diff --git a/ArdalisRating.Tests/ArdalisRating.Tests.csproj b/ArdalisRating.Tests/ArdalisRating.Tests.csproj index 0ecc9e7..ce2c983 100644 --- a/ArdalisRating.Tests/ArdalisRating.Tests.csproj +++ b/ArdalisRating.Tests/ArdalisRating.Tests.csproj @@ -1,15 +1,18 @@ - + - netcoreapp2.2 + netcoreapp3.1 false - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs index 53dbeba..c1afd29 100644 --- a/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs +++ b/ArdalisRating.Tests/JsonPolicySerializerGetPolicyFromJsonString.cs @@ -1,4 +1,5 @@ -using Xunit; +using Xunit; + namespace ArdalisRating.Tests { @@ -20,17 +21,19 @@ public void ReturnsDefaultPolicyFromEmptyJsonString() public void ReturnsSimpleAutoPolicyFromValidJsonString() { var inputJson = @"{ - ""type"": ""Auto"", - ""make"": ""BMW"" -} -"; + ""type"": ""Auto"", + ""make"": ""BMW"" + } + "; var serializer = new JsonPolicySerializer(); var result = serializer.GetPolicyFromJsonString(inputJson); - var policy = new Policy { + var policy = new Policy + { Type = "Auto", - Make = "BMW" }; + Make = "BMW" + }; AssertPoliciesEqual(result, policy); } diff --git a/ArdalisRating.Tests/RatingEngineRate.cs b/ArdalisRating.Tests/RatingEngineRate.cs index f470936..6d08f27 100644 --- a/ArdalisRating.Tests/RatingEngineRate.cs +++ b/ArdalisRating.Tests/RatingEngineRate.cs @@ -1,12 +1,48 @@ -using Newtonsoft.Json; -using System; +using Newtonsoft.Json; +using System.Collections.Generic; using System.IO; using Xunit; + namespace ArdalisRating.Tests { + // only for testing purpose + public class FakeLogger : ILogger + { + public List LoggedMessages { get; } = new List(); + + public void Log(string message) + { + LoggedMessages.Add(message); + } + } + + // Only for testing purpose + public class FakePolicySource : IPolicySource + { + public string PolicyString { get; set; } = ""; + + public string GetPolicyFromSource() + { + return PolicyString; + } + } + public class RatingEngineRate { + private readonly RatingEngine _engine; + private readonly ILogger _logger; + private readonly IPolicySource _policySource; + private IRatingContext Context { get; set; } + + public RatingEngineRate() + { + _logger = new FakeLogger(); + _policySource = new FakePolicySource(); + _engine = new RatingEngine(_logger, _policySource); + this.Context = new DefaultRatingContext(_policySource); + } + [Fact] public void ReturnsRatingOf10000For200000LandPolicy() { @@ -17,11 +53,12 @@ public void ReturnsRatingOf10000For200000LandPolicy() Valuation = 200000 }; string json = JsonConvert.SerializeObject(policy); - File.WriteAllText("policy.json", json); + //File.WriteAllText("policy.json", json); + _policySource.PolicyString = json; - var engine = new RatingEngine(); - engine.Rate(); - var result = engine.Rating; + //var engine = new RatingEngine(); + _engine.Rate(); + var result = _engine.Rating; Assert.Equal(10000, result); } @@ -31,18 +68,41 @@ public void ReturnsRatingOf0For200000BondOn260000LandPolicy() { var policy = new Policy { - //Type = PolicyType.Land, + Type = "Land", BondAmount = 200000, Valuation = 260000 }; string json = JsonConvert.SerializeObject(policy); File.WriteAllText("policy.json", json); - var engine = new RatingEngine(); - engine.Rate(); - var result = engine.Rating; + // var _engine = new RatingEngine(); + _engine.Rate(); + var result = _engine.Rating; Assert.Equal(0, result); } + + [Fact] + public void LogsStartingLoadingAndCompleting() + { + var policy = new Policy() + { + Type = "Land", + BondAmount = 2000000, + Valuation = 260000 + }; + + string json = JsonConvert.SerializeObject(policy); + File.WriteAllText("policy.json", json); + + _engine.Rate(); + var result = _engine.Rating; + + + Assert.Contains(_logger.LoggedMessages, m => m == "Starting rate."); + Assert.Contains(_logger.LoggedMessages, m => m == "Loading policy."); + Assert.Contains(_logger.LoggedMessages, m => m == "Rating completed."); + + } } } diff --git a/ArdalisRating/ArdalisRating.csproj b/ArdalisRating/ArdalisRating.csproj index a16eac7..d20b3ab 100644 --- a/ArdalisRating/ArdalisRating.csproj +++ b/ArdalisRating/ArdalisRating.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.2 + netcoreapp3.1 diff --git a/ArdalisRating/AutoPolicyRater.cs b/ArdalisRating/AutoPolicyRater.cs deleted file mode 100644 index 7b1cc52..0000000 --- a/ArdalisRating/AutoPolicyRater.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; - -namespace ArdalisRating -{ - public class AutoPolicyRater : Rater - { - public AutoPolicyRater(IRatingContext context) - : base(context) - { - } - - public override void Rate(Policy policy) - { - _logger.Log("Rating AUTO policy..."); - _logger.Log("Validating policy."); - if (String.IsNullOrEmpty(policy.Make)) - { - _logger.Log("Auto policy must specify Make"); - return; - } - if (policy.Make == "BMW") - { - if (policy.Deductible < 500) - { - _context.UpdateRating(1000m); - } - _context.UpdateRating(900m); - } - } - } -} diff --git a/ArdalisRating/Core/Interfaces/ILogger.cs b/ArdalisRating/Core/Interfaces/ILogger.cs new file mode 100644 index 0000000..aa60943 --- /dev/null +++ b/ArdalisRating/Core/Interfaces/ILogger.cs @@ -0,0 +1,8 @@ +namespace ArdalisRating +{ + public interface ILogger + { + //public List LoggedMessages { get; } + void Log(string message); + } +} diff --git a/ArdalisRating/Core/Interfaces/IPolicySerializer.cs b/ArdalisRating/Core/Interfaces/IPolicySerializer.cs new file mode 100644 index 0000000..b99c051 --- /dev/null +++ b/ArdalisRating/Core/Interfaces/IPolicySerializer.cs @@ -0,0 +1,7 @@ +namespace ArdalisRating +{ + public interface IPolicySerializer + { + public Policy GetPolicyFromJsonString(string jsonString); + } +} diff --git a/ArdalisRating/Core/Interfaces/IPolicySource.cs b/ArdalisRating/Core/Interfaces/IPolicySource.cs new file mode 100644 index 0000000..74003a3 --- /dev/null +++ b/ArdalisRating/Core/Interfaces/IPolicySource.cs @@ -0,0 +1,7 @@ +namespace ArdalisRating +{ + public interface IPolicySource + { + string GetPolicyFromSource(); + } +} diff --git a/ArdalisRating/Policy.cs b/ArdalisRating/Core/Model/Policy.cs similarity index 100% rename from ArdalisRating/Policy.cs rename to ArdalisRating/Core/Model/Policy.cs diff --git a/ArdalisRating/PolicyType.cs b/ArdalisRating/Core/Model/PolicyType.cs similarity index 100% rename from ArdalisRating/PolicyType.cs rename to ArdalisRating/Core/Model/PolicyType.cs diff --git a/ArdalisRating/Core/Rater/AutoPolicyRater.cs b/ArdalisRating/Core/Rater/AutoPolicyRater.cs new file mode 100644 index 0000000..58aa5e6 --- /dev/null +++ b/ArdalisRating/Core/Rater/AutoPolicyRater.cs @@ -0,0 +1,43 @@ +using System; + +namespace ArdalisRating +{ + public class AutoPolicyRater : Rater + { + //public AutoPolicyRater(IRatingContext context) + /* + public AutoPolicyRater(IRatingUpdater ratingUpdater, ILogger logger) + : base(ratingUpdater, logger) + { + + } + */ + public AutoPolicyRater(ILogger logger) + : base(logger) { } + + + //public override void Rate(Policy policy) + public override decimal Rate(Policy policy) + { + Logger.Log("Rating AUTO policy..."); + Logger.Log("Validating policy."); + if (String.IsNullOrEmpty(policy.Make)) + { + Logger.Log("Auto policy must specify Make"); + return 0m; + } + if (policy.Make == "BMW") + { + if (policy.Deductible < 500) + { + //_ratingUpdater.UpdateRating(1000m); + return 1000m; + } + //_ratingUpdater.UpdateRating(900m); + return 900m; + } + + return 0m; + } + } +} diff --git a/ArdalisRating/Core/Rater/FloodPolicyRater.cs b/ArdalisRating/Core/Rater/FloodPolicyRater.cs new file mode 100644 index 0000000..94e2db0 --- /dev/null +++ b/ArdalisRating/Core/Rater/FloodPolicyRater.cs @@ -0,0 +1,54 @@ +namespace ArdalisRating +{ + public class FloodPolicyRater : Rater + { + /* + public FloodPolicyRater(IRatingUpdater ratingUpdater) + : base(ratingUpdater) + { + } + */ + public FloodPolicyRater(ILogger logger) + : base(logger) + { + } + + public override decimal Rate(Policy policy) + { + // The _logger is removed and the Logger used across + //_logger.Log("Rating FLOOD policy..."); + Logger.Log("Rating FLOOD policy..."); + Logger.Log("Validating policy."); + if (policy.BondAmount == 0 || policy.Valuation == 0) + { + Logger.Log("Flood policy must specify Bond Amount and Valuation."); + return 0m; + } + if (policy.ElevationAboveSeaLevelFeet <= 0) + { + Logger.Log("Flood policy is not available for elevations at or below sea level."); + return 0m; + } + if (policy.BondAmount < 0.8m * policy.Valuation) + { + Logger.Log("Insufficient bond amount."); + return 0m; + } + decimal multiple = 1.0m; + if (policy.ElevationAboveSeaLevelFeet < 100) + { + multiple = 2.0m; + } + else if (policy.ElevationAboveSeaLevelFeet < 500) + { + multiple = 1.5m; + } + else if (policy.ElevationAboveSeaLevelFeet < 1000) + { + multiple = 1.1m; + } + //_ratingUpdater.UpdateRating(policy.BondAmount * 0.05m * multiple); + return (policy.BondAmount * 0.05m * multiple); + } + } +} diff --git a/ArdalisRating/Core/Rater/LandPolicyRater.cs b/ArdalisRating/Core/Rater/LandPolicyRater.cs new file mode 100644 index 0000000..d386464 --- /dev/null +++ b/ArdalisRating/Core/Rater/LandPolicyRater.cs @@ -0,0 +1,36 @@ +namespace ArdalisRating +{ + public class LandPolicyRater : Rater + { + + /* + public LandPolicyRater(IRatingUpdater ratingUpdater) + : base(ratingUpdater) + { + } + */ + + public LandPolicyRater(ILogger logger) + : base(logger) + { + } + + public override decimal Rate(Policy policy) + { + Logger.Log("Rating LAND policy..."); + Logger.Log("Validating policy."); + if (policy.BondAmount == 0 || policy.Valuation == 0) + { + Logger.Log("Land policy must specify Bond Amount and Valuation."); + return 0m; + } + if (policy.BondAmount < 0.8m * policy.Valuation) + { + Logger.Log("Insufficient bond amount."); + return 0m; + } + //_ratingUpdater.UpdateRating(policy.BondAmount * 0.05m); + return (policy.BondAmount * 0.05m); + } + } +} diff --git a/ArdalisRating/LifePolicyRater.cs b/ArdalisRating/Core/Rater/LifePolicyRater.cs similarity index 53% rename from ArdalisRating/LifePolicyRater.cs rename to ArdalisRating/Core/Rater/LifePolicyRater.cs index 01b2e25..68782fb 100644 --- a/ArdalisRating/LifePolicyRater.cs +++ b/ArdalisRating/Core/Rater/LifePolicyRater.cs @@ -4,29 +4,29 @@ namespace ArdalisRating { public class LifePolicyRater : Rater { - public LifePolicyRater(IRatingContext context) - : base(context) + public LifePolicyRater(ILogger logger) + : base(logger) { } - public override void Rate(Policy policy) + public override decimal Rate(Policy policy) { - _logger.Log("Rating LIFE policy..."); - _logger.Log("Validating policy."); + Logger.Log("Rating LIFE policy..."); + Logger.Log("Validating policy."); if (policy.DateOfBirth == DateTime.MinValue) { - _logger.Log("Life policy must include Date of Birth."); - return; + Logger.Log("Life policy must include Date of Birth."); + return 0m; } if (policy.DateOfBirth < DateTime.Today.AddYears(-100)) { - _logger.Log("Centenarians are not eligible for coverage."); - return; + Logger.Log("Centenarians are not eligible for coverage."); + return 0m; } if (policy.Amount == 0) { - _logger.Log("Life policy must include an Amount."); - return; + Logger.Log("Life policy must include an Amount."); + return 0m; } int age = DateTime.Today.Year - policy.DateOfBirth.Year; if (policy.DateOfBirth.Month == DateTime.Today.Month && @@ -38,10 +38,11 @@ public override void Rate(Policy policy) decimal baseRate = policy.Amount * age / 200; if (policy.IsSmoker) { - _context.UpdateRating(baseRate * 2); - return; + //_ratingUpdater.UpdateRating(baseRate * 2); + return (baseRate * 2); } - _context.UpdateRating(baseRate); + //_ratingUpdater.UpdateRating(baseRate); + return (baseRate); } } } diff --git a/ArdalisRating/Core/Rater/Rater.cs b/ArdalisRating/Core/Rater/Rater.cs new file mode 100644 index 0000000..65730d3 --- /dev/null +++ b/ArdalisRating/Core/Rater/Rater.cs @@ -0,0 +1,37 @@ +namespace ArdalisRating +{ + public abstract class Rater + { + //protected readonly IRatingContext _context; + //protected readonly IRatingUpdater _ratingUpdater; + + //protected readonly ConsoleLogger _logger; + + + + // protected ILogger Logger { get; set; } = new ConsoleLogger(); + public ILogger Logger { get; set; } + + /* + public Rater(ILogger logger) + { + Logger = logger; + } + */ + + //public Rater(IRatingContext context) + //public Rater(IRatingUpdater ratingUpdater, ILogger logger) + //public Rater(IRatingUpdater ratingUpdater) + public Rater(ILogger logger) + { + //_context = context; + //_ratingUpdater = ratingUpdater; + + //_logger = _context.Logger; + Logger = logger; + } + + //public abstract void Rate(Policy policy); + public abstract decimal Rate(Policy policy); + } +} diff --git a/ArdalisRating/Core/Rater/RaterFactory.cs b/ArdalisRating/Core/Rater/RaterFactory.cs new file mode 100644 index 0000000..6f6b105 --- /dev/null +++ b/ArdalisRating/Core/Rater/RaterFactory.cs @@ -0,0 +1,39 @@ +using System; + +namespace ArdalisRating +{ + public class RaterFactory + { + private readonly IRatingUpdater _ratingUpdater; + private readonly ILogger _logger; + + //public Rater Create(Policy policy, IRatingContext context) + + //public RaterFactory(IRatingUpdater ratingUpdater) + public RaterFactory(ILogger logger) + { + //_ratingUpdater = ratingUpdater; + _logger = logger; + } + public Rater Create(Policy policy) + { + try + { + /* + return (Rater)Activator.CreateInstance( + Type.GetType($"ArdalisRating.{policy.Type}PolicyRater"), + new object[] { context }); + */ + return (Rater)Activator.CreateInstance( + Type.GetType($"ArdalisRating.{policy.Type}PolicyRater"), + new object[] { _logger }); + + } + catch + { + //return new UnknownPolicyRater(context); + return new UnknownPolicyRater(_logger); + } + } + } +} diff --git a/ArdalisRating/Core/Rater/UnknownPolicyRater.cs b/ArdalisRating/Core/Rater/UnknownPolicyRater.cs new file mode 100644 index 0000000..6fe923b --- /dev/null +++ b/ArdalisRating/Core/Rater/UnknownPolicyRater.cs @@ -0,0 +1,32 @@ +namespace ArdalisRating +{ + public class UnknownPolicyRater : Rater + { + /* + public UnknownPolicyRater(IRatingContext context) + : base(context) + { + } + */ + + /* + public UnknownPolicyRater(IRatingUpdater ratingUpdater) + : base(ratingUpdater) + { + + } + */ + public UnknownPolicyRater(ILogger logger) + : base(logger) + { + + } + + + public override decimal Rate(Policy policy) + { + Logger.Log("Unknown policy type"); + return 0m; + } + } +} diff --git a/ArdalisRating/Core/RatingEngine.cs b/ArdalisRating/Core/RatingEngine.cs new file mode 100644 index 0000000..70d5412 --- /dev/null +++ b/ArdalisRating/Core/RatingEngine.cs @@ -0,0 +1,60 @@ +namespace ArdalisRating +{ + /// + /// The RatingEngine reads the policy application details from a file and produces a numeric + /// rating value based on the details. + /// + public class RatingEngine + { + private readonly ILogger _logger; + private readonly IPolicySource _policySource; + private readonly IPolicySerializer _policySerializer; + private readonly RaterFactory _factory; + + + //public IRatingContext Context { get; set; } = new DefaultRatingContext(); + public IRatingContext Context { get; set; } + public decimal Rating { get; set; } + + /* + public RatingEngine() : this(new ConsoleLogger()) + { + // default Ctor; + // chaining ctor to include the one parameter constructor + } + */ + + public RatingEngine(ILogger logger, IPolicySource policySource, IPolicySerializer policySerializer, RaterFactory factory) + { + _policySource = policySource; + _policySerializer = policySerializer; + //Context = new DefaultRatingContext(_policySource, _policySerializer, logger); + //Context.Engine = this; + _logger = logger; + _factory = factory; + } + + public void Rate() + { + _logger.Log("Starting rate."); + + // Rather than using the Context instance, explicitly adding dependecies as constructor + // Context.Log("Loading policy."); + _logger.Log("Loading policy."); + + //string policyJson = Context.LoadPolicyFromFile(); + string policyJson = _policySource.GetPolicyFromSource(); + + //var policy = Context.GetPolicyFromJsonString(policyJson); + var policy = _policySerializer.GetPolicyFromJsonString(policyJson); + + + //var rater = Context.CreateRaterForPolicy(policy, Context); + var rater = _factory.Create(policy); + + rater.Rate(policy); + + _logger.Log("Rating completed."); + } + } +} diff --git a/ArdalisRating/DefaultRatingContext.cs b/ArdalisRating/DefaultRatingContext.cs index eaf8235..d894f5c 100644 --- a/ArdalisRating/DefaultRatingContext.cs +++ b/ArdalisRating/DefaultRatingContext.cs @@ -6,16 +6,30 @@ public class DefaultRatingContext : IRatingContext { public RatingEngine Engine { get; set; } - public ConsoleLogger Logger => new ConsoleLogger(); + //public ConsoleLogger Logger => new ConsoleLogger(); + + // DIP made change + private readonly IPolicySource _policySource; + private readonly IPolicySerializer _policySerializer; + private readonly ILogger _logger; + + public DefaultRatingContext(IPolicySource policySource, IPolicySerializer policySerializer, ILogger logger) + { + _policySource = policySource; + _policySerializer = policySerializer; + _logger = logger; + } public Rater CreateRaterForPolicy(Policy policy, IRatingContext context) { - return new RaterFactory().Create(policy, context); + //return new RaterFactory().Create(policy, context); + return new RaterFactory(_logger).Create(policy); } public Policy GetPolicyFromJsonString(string policyJson) { - return new JsonPolicySerializer().GetPolicyFromJsonString(policyJson); + //return new JsonPolicySerializer().GetPolicyFromJsonString(policyJson); + return _policySerializer.GetPolicyFromJsonString(policyJson); } public Policy GetPolicyFromXmlString(string policyXml) @@ -25,7 +39,8 @@ public Policy GetPolicyFromXmlString(string policyXml) public string LoadPolicyFromFile() { - return new FilePolicySource().GetPolicyFromSource(); + // return new FilePolicySource().GetPolicyFromSource(); + return _policySource.GetPolicyFromSource(); } public string LoadPolicyFromURI(string uri) @@ -33,11 +48,11 @@ public string LoadPolicyFromURI(string uri) throw new NotImplementedException(); } + public void Log(string message) { new ConsoleLogger().Log(message); } - public void UpdateRating(decimal rating) { Engine.Rating = rating; diff --git a/ArdalisRating/FloodPolicyRater.cs b/ArdalisRating/FloodPolicyRater.cs deleted file mode 100644 index 7b5c37b..0000000 --- a/ArdalisRating/FloodPolicyRater.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace ArdalisRating -{ - public class FloodPolicyRater : Rater - { - public FloodPolicyRater(IRatingContext context) - : base(context) - { - } - - public override void Rate(Policy policy) - { - _logger.Log("Rating FLOOD policy..."); - _logger.Log("Validating policy."); - if (policy.BondAmount == 0 || policy.Valuation == 0) - { - _logger.Log("Flood policy must specify Bond Amount and Valuation."); - return; - } - if (policy.ElevationAboveSeaLevelFeet <= 0) - { - _logger.Log("Flood policy is not available for elevations at or below sea level."); - return; - } - if (policy.BondAmount < 0.8m * policy.Valuation) - { - _logger.Log("Insufficient bond amount."); - return; - } - decimal multiple = 1.0m; - if(policy.ElevationAboveSeaLevelFeet < 100) - { - multiple = 2.0m; - } else if (policy.ElevationAboveSeaLevelFeet < 500) - { - multiple = 1.5m; - } else if (policy.ElevationAboveSeaLevelFeet < 1000) - { - multiple = 1.1m; - } - _context.UpdateRating(policy.BondAmount * 0.05m * multiple); - } - } -} diff --git a/ArdalisRating/IRatingContext.cs b/ArdalisRating/IRatingContext.cs index aab2602..ea0f11f 100644 --- a/ArdalisRating/IRatingContext.cs +++ b/ArdalisRating/IRatingContext.cs @@ -1,15 +1,16 @@ namespace ArdalisRating { - public interface IRatingContext + public interface IRatingContext : ILogger, IRatingUpdater { - void Log(string message); + // Removing both the logging options since it is available in ILogger + //void Log(string message); string LoadPolicyFromFile(); string LoadPolicyFromURI(string uri); Policy GetPolicyFromJsonString(string policyJson); Policy GetPolicyFromXmlString(string policyXml); Rater CreateRaterForPolicy(Policy policy, IRatingContext context); - void UpdateRating(decimal rating); + //void UpdateRating(decimal rating); RatingEngine Engine { get; set; } - ConsoleLogger Logger { get; } + //ConsoleLogger Logger { get; } } } diff --git a/ArdalisRating/IRatingUpdater.cs b/ArdalisRating/IRatingUpdater.cs new file mode 100644 index 0000000..85035e0 --- /dev/null +++ b/ArdalisRating/IRatingUpdater.cs @@ -0,0 +1,7 @@ +namespace ArdalisRating +{ + public interface IRatingUpdater + { + void UpdateRating(decimal rating); + } +} diff --git a/ArdalisRating/ConsoleLogger.cs b/ArdalisRating/Infrastructure/Loggers/ConsoleLogger.cs similarity index 79% rename from ArdalisRating/ConsoleLogger.cs rename to ArdalisRating/Infrastructure/Loggers/ConsoleLogger.cs index ecfafa0..795652c 100644 --- a/ArdalisRating/ConsoleLogger.cs +++ b/ArdalisRating/Infrastructure/Loggers/ConsoleLogger.cs @@ -2,7 +2,7 @@ namespace ArdalisRating { - public class ConsoleLogger + public class ConsoleLogger : ILogger { public void Log(string message) { diff --git a/ArdalisRating/Infrastructure/Loggers/FileLogger.cs b/ArdalisRating/Infrastructure/Loggers/FileLogger.cs new file mode 100644 index 0000000..ee30955 --- /dev/null +++ b/ArdalisRating/Infrastructure/Loggers/FileLogger.cs @@ -0,0 +1,16 @@ +using System.IO; + +namespace ArdalisRating +{ + public class FileLogger : ILogger + { + public void Log(string message) + { + using (var stream = File.AppendText("log.txt")) + { + stream.WriteLine(message); + stream.Flush(); + } + } + } +} diff --git a/ArdalisRating/FilePolicySource.cs b/ArdalisRating/Infrastructure/PolicySources/FilePolicySource.cs similarity index 77% rename from ArdalisRating/FilePolicySource.cs rename to ArdalisRating/Infrastructure/PolicySources/FilePolicySource.cs index a0ff64f..cbfb698 100644 --- a/ArdalisRating/FilePolicySource.cs +++ b/ArdalisRating/Infrastructure/PolicySources/FilePolicySource.cs @@ -2,7 +2,7 @@ namespace ArdalisRating { - public class FilePolicySource + public class FilePolicySource : IPolicySource { public string GetPolicyFromSource() { diff --git a/ArdalisRating/JsonPolicySerializer.cs b/ArdalisRating/Infrastructure/Serializers/JsonPolicySerializer.cs similarity index 83% rename from ArdalisRating/JsonPolicySerializer.cs rename to ArdalisRating/Infrastructure/Serializers/JsonPolicySerializer.cs index b068d75..9258f2f 100644 --- a/ArdalisRating/JsonPolicySerializer.cs +++ b/ArdalisRating/Infrastructure/Serializers/JsonPolicySerializer.cs @@ -3,7 +3,7 @@ namespace ArdalisRating { - public class JsonPolicySerializer + public class JsonPolicySerializer : IPolicySerializer { public Policy GetPolicyFromJsonString(string jsonString) { diff --git a/ArdalisRating/LandPolicyRater.cs b/ArdalisRating/LandPolicyRater.cs deleted file mode 100644 index b346831..0000000 --- a/ArdalisRating/LandPolicyRater.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace ArdalisRating -{ - public class LandPolicyRater : Rater - { - public LandPolicyRater(IRatingContext context) - :base(context) - { - } - - public override void Rate(Policy policy) - { - _logger.Log("Rating LAND policy..."); - _logger.Log("Validating policy."); - if (policy.BondAmount == 0 || policy.Valuation == 0) - { - _logger.Log("Land policy must specify Bond Amount and Valuation."); - return; - } - if (policy.BondAmount < 0.8m * policy.Valuation) - { - _logger.Log("Insufficient bond amount."); - return; - } - _context.UpdateRating(policy.BondAmount * 0.05m); - } - } -} diff --git a/ArdalisRating/Rater.cs b/ArdalisRating/Rater.cs deleted file mode 100644 index 1932f97..0000000 --- a/ArdalisRating/Rater.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ArdalisRating -{ - public abstract class Rater - { - protected readonly IRatingContext _context; - protected readonly ConsoleLogger _logger; - - public Rater(IRatingContext context) - { - _context = context; - _logger = _context.Logger; - } - - public abstract void Rate(Policy policy); - } -} diff --git a/ArdalisRating/RaterFactory.cs b/ArdalisRating/RaterFactory.cs deleted file mode 100644 index eed7828..0000000 --- a/ArdalisRating/RaterFactory.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace ArdalisRating -{ - public class RaterFactory - { - public Rater Create(Policy policy, IRatingContext context) - { - try - { - return (Rater)Activator.CreateInstance( - Type.GetType($"ArdalisRating.{policy.Type}PolicyRater"), - new object[] { context }); - } - catch - { - return new UnknownPolicyRater(context); - } - } - } -} diff --git a/ArdalisRating/RatingEngine.cs b/ArdalisRating/RatingEngine.cs deleted file mode 100644 index 9752592..0000000 --- a/ArdalisRating/RatingEngine.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace ArdalisRating -{ - /// - /// The RatingEngine reads the policy application details from a file and produces a numeric - /// rating value based on the details. - /// - public class RatingEngine - { - public IRatingContext Context { get; set; } = new DefaultRatingContext(); - public decimal Rating { get; set; } - public RatingEngine() - { - Context.Engine = this; - } - public void Rate() - { - Context.Log("Starting rate."); - - Context.Log("Loading policy."); - - string policyJson = Context.LoadPolicyFromFile(); - - var policy = Context.GetPolicyFromJsonString(policyJson); - - var rater = Context.CreateRaterForPolicy(policy, Context); - - rater.Rate(policy); - - Context.Log("Rating completed."); - } - } -} diff --git a/ArdalisRating/RatingUpdater.cs b/ArdalisRating/RatingUpdater.cs new file mode 100644 index 0000000..d21cd92 --- /dev/null +++ b/ArdalisRating/RatingUpdater.cs @@ -0,0 +1,17 @@ +namespace ArdalisRating +{ + public class RatingUpdater : IRatingUpdater + { + private readonly RatingEngine _engine; + + public RatingUpdater(RatingEngine engine) + { + _engine = engine; + } + + public void UpdateRating(decimal rating) + { + _engine.Rating = rating; + } + } +} diff --git a/ArdalisRating/Program.cs b/ArdalisRating/UI/Program.cs similarity index 65% rename from ArdalisRating/Program.cs rename to ArdalisRating/UI/Program.cs index af231a9..3db971e 100644 --- a/ArdalisRating/Program.cs +++ b/ArdalisRating/UI/Program.cs @@ -7,8 +7,10 @@ class Program static void Main(string[] args) { Console.WriteLine("Ardalis Insurance Rating System Starting..."); + //var logger = new ConsoleLogger(); + var logger = new FileLogger(); - var engine = new RatingEngine(); + var engine = new RatingEngine(logger, new FilePolicySource(), new JsonPolicySerializer(), new RaterFactory(logger)); engine.Rate(); if (engine.Rating > 0) @@ -20,6 +22,7 @@ static void Main(string[] args) Console.WriteLine("No rating produced."); } + Console.ReadLine(); } } } diff --git a/ArdalisRating/UnknownPolicyRater.cs b/ArdalisRating/UnknownPolicyRater.cs deleted file mode 100644 index 1b07919..0000000 --- a/ArdalisRating/UnknownPolicyRater.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ArdalisRating -{ - public class UnknownPolicyRater : Rater - { - public UnknownPolicyRater(IRatingContext context) - : base(context) - { - } - - public override void Rate(Policy policy) - { - _logger.Log("Unknown policy type"); - } - } -} diff --git a/ArdalisRating/policy.json b/ArdalisRating/policy.json index a02f104..c138e8b 100644 --- a/ArdalisRating/policy.json +++ b/ArdalisRating/policy.json @@ -1,6 +1,5 @@ { - "type": "Flood", + "type": "Land", "bondAmount": "1000000", - "valuation": "1100000", - "elevationAboveSeaLevelFeet": "1001" + "valuation": "1100000" }