diff --git a/DependencyInversion_Shared/Alarms/IAlarm.cs b/DependencyInversion_Shared/Alarms/IAlarm.cs deleted file mode 100644 index 5d38754..0000000 --- a/DependencyInversion_Shared/Alarms/IAlarm.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace DependencyInversion -{ - public interface IAlarm - { - void RaiseAlarm(); - } -} \ No newline at end of file diff --git a/DependencyInversion_Shared/DependencyInversion_Shared.projitems b/DependencyInversion_Shared/DependencyInversion_Shared.projitems index 3b97d32..dbb80b9 100644 --- a/DependencyInversion_Shared/DependencyInversion_Shared.projitems +++ b/DependencyInversion_Shared/DependencyInversion_Shared.projitems @@ -9,20 +9,17 @@ DependencyInversion_Shared - - - - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/DependencyInversion_Shared/Sensors/ISensor.cs b/DependencyInversion_Shared/Sensors/ISensor.cs deleted file mode 100644 index d8b4c51..0000000 --- a/DependencyInversion_Shared/Sensors/ISensor.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace DependencyInversion -{ - public interface ISensor - { - void AttachAlarm(IAlarm sensorAlarm); - - void RaiseAlarms(); - } - -} \ No newline at end of file diff --git a/DependencyInversion_Shared/Sensors/Sensor.cs b/DependencyInversion_Shared/Sensors/Sensor.cs deleted file mode 100644 index 60599a3..0000000 --- a/DependencyInversion_Shared/Sensors/Sensor.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Collections.Generic; - -namespace DependencyInversion -{ - public class Sensor : ISensor - { - protected List _sensorAlarms = new(); - - public void AttachAlarm(IAlarm sensorAlarm) - { - _sensorAlarms.Add(sensorAlarm); - } - - public void RaiseAlarms() - { - _sensorAlarms.ForEach(alarm => alarm.RaiseAlarm()); - } - } -} \ No newline at end of file diff --git a/DependencyInversion_Shared/Sensors/TemperatureSensor.cs b/DependencyInversion_Shared/Sensors/TemperatureSensor.cs deleted file mode 100644 index 827d7c1..0000000 --- a/DependencyInversion_Shared/Sensors/TemperatureSensor.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; - -namespace DependencyInversion -{ - public sealed class TemperatureSensor : Sensor - { - public string Id { get; private set; } - - public TemperatureSensor(string sensorId) - { - Id = sensorId; - } - - /// - /// Get the current temperature of the sensor. - /// - /// the current temperature - /// - /// We'll just pretend we're physically hooked up to a sensor, and that this method will return its current temperature. - /// - public double GetTemperature() - { - Random rnd = new(); - return rnd.NextDouble(); - } - } -} \ No newline at end of file diff --git a/DependencyInversion_Shared/Sensors/TemperatureSensorData.cs b/DependencyInversion_Shared/Sensors/TemperatureSensorData.cs deleted file mode 100644 index bfdc154..0000000 --- a/DependencyInversion_Shared/Sensors/TemperatureSensorData.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace DependencyInversion -{ - public record struct TemperatureSensorData(string SensorId, double Temperature); - -} \ No newline at end of file diff --git a/DependencyInversion_Shared/Alarms/DisplayAlarm.cs b/DependencyInversion_Shared/SpellAlarms/DisplayAlarm.cs similarity index 56% rename from DependencyInversion_Shared/Alarms/DisplayAlarm.cs rename to DependencyInversion_Shared/SpellAlarms/DisplayAlarm.cs index f89ad6f..918d670 100644 --- a/DependencyInversion_Shared/Alarms/DisplayAlarm.cs +++ b/DependencyInversion_Shared/SpellAlarms/DisplayAlarm.cs @@ -1,11 +1,10 @@ -using DependencyInversion; -using System.Diagnostics; +using System.Diagnostics; namespace DependencyInversion { - public sealed class DisplayAlarm : IAlarm + public sealed class DisplayAlarm : ISpellAlarm { - public void RaiseAlarm() + public void RaiseSpellAlarm() { // we'll just pretend to raise an alarm here. Debug.WriteLine("An alarm was raised"); diff --git a/DependencyInversion_Shared/Alarms/EnhancedDisplayAlarm.cs b/DependencyInversion_Shared/SpellAlarms/EnhancedDisplayAlarm.cs similarity index 69% rename from DependencyInversion_Shared/Alarms/EnhancedDisplayAlarm.cs rename to DependencyInversion_Shared/SpellAlarms/EnhancedDisplayAlarm.cs index bdf1aad..2d5bf43 100644 --- a/DependencyInversion_Shared/Alarms/EnhancedDisplayAlarm.cs +++ b/DependencyInversion_Shared/SpellAlarms/EnhancedDisplayAlarm.cs @@ -2,9 +2,9 @@ namespace DependencyInversion { - public sealed class EnhancedDisplayAlarm : IAlarm + public sealed class EnhancedDisplayAlarm : ISpellAlarm { - public void RaiseAlarm() + public void RaiseSpellAlarm() { // we'll just pretend to raise an alarm here. Debug.WriteLine("AN ALARM WAS RAISED, GOD DAMMIT!!!"); diff --git a/DependencyInversion_Shared/SpellAlarms/IAlarm.cs b/DependencyInversion_Shared/SpellAlarms/IAlarm.cs new file mode 100644 index 0000000..2618e06 --- /dev/null +++ b/DependencyInversion_Shared/SpellAlarms/IAlarm.cs @@ -0,0 +1,7 @@ +namespace DependencyInversion +{ + public interface ISpellAlarm + { + void RaiseSpellAlarm(); + } +} \ No newline at end of file diff --git a/DependencyInversion_Shared/Alarms/PersistentBeepAlarm.cs b/DependencyInversion_Shared/SpellAlarms/PersistentBeepAlarm.cs similarity index 70% rename from DependencyInversion_Shared/Alarms/PersistentBeepAlarm.cs rename to DependencyInversion_Shared/SpellAlarms/PersistentBeepAlarm.cs index c73f211..f7fa707 100644 --- a/DependencyInversion_Shared/Alarms/PersistentBeepAlarm.cs +++ b/DependencyInversion_Shared/SpellAlarms/PersistentBeepAlarm.cs @@ -2,9 +2,9 @@ namespace DependencyInversion { - public sealed class PersistentBeepAlarm : IAlarm + public sealed class PersistentBeepAlarm : ISpellAlarm { - public void RaiseAlarm() + public void RaiseSpellAlarm() { int i = 0; do diff --git a/DependencyInversion_Shared/Alarms/WarningBellAlarm.cs b/DependencyInversion_Shared/SpellAlarms/WarningBellAlarm.cs similarity index 54% rename from DependencyInversion_Shared/Alarms/WarningBellAlarm.cs rename to DependencyInversion_Shared/SpellAlarms/WarningBellAlarm.cs index 99e1e2d..3e4092d 100644 --- a/DependencyInversion_Shared/Alarms/WarningBellAlarm.cs +++ b/DependencyInversion_Shared/SpellAlarms/WarningBellAlarm.cs @@ -2,9 +2,9 @@ namespace DependencyInversion { - public sealed class WarningBellAlarm : IAlarm + public sealed class WarningBellAlarm : ISpellAlarm { - public void RaiseAlarm() + public void RaiseSpellAlarm() { Console.Beep(); } diff --git a/DependencyInversion_Shared/Spells/ISpell.cs b/DependencyInversion_Shared/Spells/ISpell.cs new file mode 100644 index 0000000..a6bdeba --- /dev/null +++ b/DependencyInversion_Shared/Spells/ISpell.cs @@ -0,0 +1,10 @@ +namespace DependencyInversion +{ + public interface ISpell + { + void AttachSpellAlarm(ISpellAlarm spellAlarm); + + void RaiseSpellAlarms(); + } + +} \ No newline at end of file diff --git a/DependencyInversion_Shared/Sensors/PressureSensor.cs b/DependencyInversion_Shared/Spells/PressureSpell.cs similarity index 50% rename from DependencyInversion_Shared/Sensors/PressureSensor.cs rename to DependencyInversion_Shared/Spells/PressureSpell.cs index cc97662..0516a66 100644 --- a/DependencyInversion_Shared/Sensors/PressureSensor.cs +++ b/DependencyInversion_Shared/Spells/PressureSpell.cs @@ -1,6 +1,6 @@ namespace DependencyInversion { - public sealed class PressureSensor : Sensor + public sealed class PressureSpell : Spell { } } \ No newline at end of file diff --git a/DependencyInversion_Shared/Spells/Spell.cs b/DependencyInversion_Shared/Spells/Spell.cs new file mode 100644 index 0000000..2cb7071 --- /dev/null +++ b/DependencyInversion_Shared/Spells/Spell.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; + +namespace DependencyInversion +{ + public class Spell : ISpell + { + protected List _spellAlarms = new(); + + public void AttachSpellAlarm(ISpellAlarm spellAlarm) + { + _spellAlarms.Add(spellAlarm); + } + + public void RaiseSpellAlarms() + { + _spellAlarms.ForEach(alarm => alarm.RaiseSpellAlarm()); + } + } +} \ No newline at end of file diff --git a/DependencyInversion_Shared/Spells/TemperatureSpell.cs b/DependencyInversion_Shared/Spells/TemperatureSpell.cs new file mode 100644 index 0000000..626df70 --- /dev/null +++ b/DependencyInversion_Shared/Spells/TemperatureSpell.cs @@ -0,0 +1,23 @@ +using System; + +namespace DependencyInversion +{ + public sealed class TemperatureSpell : Spell + { + public string Id { get; private set; } + + public TemperatureSpell(string spellId) + { + Id = spellId; + } + + /// + /// Get the current temperature of the spell. + /// + public double GetTemperature() + { + Random rnd = new(); + return rnd.NextDouble(); + } + } +} \ No newline at end of file diff --git a/DependencyInversion_Shared/Spells/TemperatureSpellData.cs b/DependencyInversion_Shared/Spells/TemperatureSpellData.cs new file mode 100644 index 0000000..77868e2 --- /dev/null +++ b/DependencyInversion_Shared/Spells/TemperatureSpellData.cs @@ -0,0 +1,5 @@ +namespace DependencyInversion +{ + public record struct TemperatureSpellData(string SpellId, double SpellTemperature); + +} \ No newline at end of file diff --git a/DependencyInversion_Shared/TemperatureSensorLogger.cs b/DependencyInversion_Shared/TemperatureSensorLogger.cs deleted file mode 100644 index 97fa127..0000000 --- a/DependencyInversion_Shared/TemperatureSensorLogger.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace DependencyInversion -{ - /// - /// A logger that writes temperature sensor data. - /// - public sealed class TemperatureSensorLogger - { - private readonly DiagnosticsLogger _diagnosticsLogger; - - public TemperatureSensorLogger(DiagnosticsLogger diagnosticsLogger) - { - _diagnosticsLogger = diagnosticsLogger; - } - - /// - /// Write sensor data for all temperature-sensors. - /// - public void WriteAllTemperatureSensorsDataToLog(IEnumerable temperatureSensorDataList) - { - foreach(TemperatureSensorData temperatureSensorData in temperatureSensorDataList) - { - string logMessage = $"Sensor {temperatureSensorData.SensorId} reported value {temperatureSensorData.Temperature:N2}"; - _diagnosticsLogger.WriteToLog(logMessage); - } - } - } -} \ No newline at end of file diff --git a/DependencyInversion_Shared/TemperatureSpellLogger.cs b/DependencyInversion_Shared/TemperatureSpellLogger.cs new file mode 100644 index 0000000..4d35d26 --- /dev/null +++ b/DependencyInversion_Shared/TemperatureSpellLogger.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace DependencyInversion +{ + /// + /// A logger that writes temperature spell data. + /// + public sealed class TemperatureSpellLogger + { + private readonly DiagnosticsLogger _diagnosticsLogger; + + public TemperatureSpellLogger(DiagnosticsLogger diagnosticsLogger) + { + _diagnosticsLogger = diagnosticsLogger; + } + + /// + /// Write data for all temperature-sensors to the log. + /// + public void WriteAllTemperatureSpellsDataToLog(IEnumerable temperatureSpellsData) + { + foreach(TemperatureSpellData spellData in temperatureSpellsData) + { + string logMessage = $"Spell {spellData.SpellId} reported value {spellData.SpellTemperature:N2}"; + _diagnosticsLogger.WriteToLog(logMessage); + } + } + } +} \ No newline at end of file diff --git a/DesignPatterns/BehaviourPatterns/StrategyPattern/StrategyPattern_example/StrategyPatern_problem/Program.cs b/DesignPatterns/BehaviourPatterns/StrategyPattern/StrategyPattern_example/StrategyPatern_problem/Program.cs index f93fdac..6584b91 100644 --- a/DesignPatterns/BehaviourPatterns/StrategyPattern/StrategyPattern_example/StrategyPatern_problem/Program.cs +++ b/DesignPatterns/BehaviourPatterns/StrategyPattern/StrategyPattern_example/StrategyPatern_problem/Program.cs @@ -1,19 +1,21 @@ using StrategyPattern; using System.Diagnostics; -namespace StrategyPatern_problem +namespace StrategyPattern_problem { public sealed class Program { /// - /// Dilemma: we need to calculate a 'user reputation' for our dating service users, based on which type of member they are. How do we go about that in the best, most flexible way? In the below example, the DatingUser-class shifts between types to accomodate different UserReputation values. + /// Dilemma: we need to calculate a 'user reputation' for our dating service users, based on which type of member they are. + /// How do we go about that in the best, most flexible way? In the below example, the DatingUser-class shifts between types to accommodate different UserReputation values. /// private static void Main() { - DatingUser someUser = new(); - - someUser.NumberOfAnsweredQuestions = 3; - someUser.userReputation = UserReputationEnum.BasicUserReputation; + DatingUser someUser = new() + { + NumberOfAnsweredQuestions = 3, + userReputation = UserReputationEnum.BasicUserReputation + }; int calculatedReputation = someUser.CalculateReputation(); diff --git a/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challenge/Program.cs b/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challenge/Program.cs index e33b3b3..c4037c8 100644 --- a/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challenge/Program.cs +++ b/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challenge/Program.cs @@ -1,6 +1,4 @@ -using System; -using System.Diagnostics; -using TemplatePattern; +using TemplatePattern; namespace TemplatePattern_challenge { diff --git a/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challengeSolved/Member.cs b/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challengeSolved/Member.cs index 5af1cc0..a7e6cca 100644 --- a/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challengeSolved/Member.cs +++ b/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challengeSolved/Member.cs @@ -1,6 +1,4 @@ -using System; - -namespace TemplatePattern +namespace TemplatePattern { public struct Member { diff --git a/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challengeSolved/MemberNotificationBase.cs b/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challengeSolved/MemberNotificationBase.cs index 667f6ec..ff8ba45 100644 --- a/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challengeSolved/MemberNotificationBase.cs +++ b/DesignPatterns/BehaviourPatterns/TemplateMethodPattern/TemplateMethod_example/TemplatePattern_challengeSolved/MemberNotificationBase.cs @@ -1,7 +1,4 @@ -using System; -using System.Diagnostics; - -namespace TemplatePattern +namespace TemplatePattern { // The Template Pattern lets us define a series of common steps, deferring some steps to sub-classes. // Let's redo the notifications in the style of the pattern: diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/BasicUserAuthenticator.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/BasicUserAuthenticator.cs index 162f80d..22ab099 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/BasicUserAuthenticator.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/BasicUserAuthenticator.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace FactoryPattern +namespace FactoryPattern { public class BasicUserAuthenticator : IAuthenticator { diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/BasicUserAuthorizer.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/BasicUserAuthorizer.cs index 125ebe6..3e1bd7d 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/BasicUserAuthorizer.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/BasicUserAuthorizer.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace FactoryPattern +namespace FactoryPattern { public sealed class BasicUserAuthorizer : IAuthorizer { diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/SuperUserAuthenticator.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/SuperUserAuthenticator.cs index 52d666f..f588a79 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/SuperUserAuthenticator.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/SuperUserAuthenticator.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace FactoryPattern +namespace FactoryPattern { public class SuperUserAuthenticator : IAuthenticator { diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/SuperUserAuthorizer.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/SuperUserAuthorizer.cs index 8e4b850..c404a89 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/SuperUserAuthorizer.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/SuperUserAuthorizer.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace FactoryPattern +namespace FactoryPattern { public sealed class SuperUserAuthorizer : IAuthorizer { diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/UserSecurityManager.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/UserSecurityManager.cs index 59162b9..f12beba 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/UserSecurityManager.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challenge/UserSecurityManager.cs @@ -1,5 +1,4 @@ using FactoryPattern; -using System; namespace AbstractFactoryPattern { diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/BasicUserAuthenticator.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/BasicUserAuthenticator.cs index c353be1..66145ae 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/BasicUserAuthenticator.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/BasicUserAuthenticator.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace AbstractFactoryPattern +namespace AbstractFactoryPattern { public class BasicUserAuthenticator : IAuthenticator { diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/BasicUserAuthorizer.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/BasicUserAuthorizer.cs index 3f5dba0..15e1531 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/BasicUserAuthorizer.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/BasicUserAuthorizer.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace AbstractFactoryPattern +namespace AbstractFactoryPattern { public sealed class BasicUserAuthorizer : IAuthorizer { diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/Program.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/Program.cs index c69b937..f390765 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/Program.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/Program.cs @@ -1,6 +1,4 @@ -using System; - -namespace AbstractFactoryPattern +namespace AbstractFactoryPattern { public sealed class Program { diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/SuperUserAuthenticator.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/SuperUserAuthenticator.cs index 5316eda..ac91da2 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/SuperUserAuthenticator.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/SuperUserAuthenticator.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace AbstractFactoryPattern +namespace AbstractFactoryPattern { public class SuperUserAuthenticator : IAuthenticator { diff --git a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/SuperUserAuthorizer.cs b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/SuperUserAuthorizer.cs index 8e714fa..382811d 100644 --- a/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/SuperUserAuthorizer.cs +++ b/DesignPatterns/CreationalPatterns/AbstractFactoryPattern/AbstractFactoryPattern_example/AbstractFactory_challengeSolved/SuperUserAuthorizer.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace AbstractFactoryPattern +namespace AbstractFactoryPattern { public sealed class SuperUserAuthorizer : IAuthorizer { diff --git a/DesignPatterns/StructuralPatterns/CompositePattern/CompositePattern_example/CompositePatern_challenge/Program.cs b/DesignPatterns/StructuralPatterns/CompositePattern/CompositePattern_example/CompositePatern_challenge/Program.cs index c3487fa..5e61783 100644 --- a/DesignPatterns/StructuralPatterns/CompositePattern/CompositePattern_example/CompositePatern_challenge/Program.cs +++ b/DesignPatterns/StructuralPatterns/CompositePattern/CompositePattern_example/CompositePatern_challenge/Program.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace CompositePatern_challenge { diff --git a/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/Program.cs b/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/Program.cs index 9273bd1..8225a72 100644 --- a/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/Program.cs +++ b/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/Program.cs @@ -1,5 +1,4 @@ using DecoratorPattern; -using System.Diagnostics; namespace DecoratorPattern_challengeSolved { diff --git a/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/WithAnniversaryDecorator.cs b/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/WithAnniversaryDecorator.cs index 2efc6a4..492e10c 100644 --- a/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/WithAnniversaryDecorator.cs +++ b/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/WithAnniversaryDecorator.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace DecoratorPattern +namespace DecoratorPattern { public class WithAnniversaryDecorator : MemberDecoratorbase { diff --git a/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/WithSpecialOfferDecorator.cs b/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/WithSpecialOfferDecorator.cs index a0cc682..9afd38d 100644 --- a/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/WithSpecialOfferDecorator.cs +++ b/DesignPatterns/StructuralPatterns/DecoratorPattern/DecoratorPattern_example/DecoratorPattern_challengeSolved/WithSpecialOfferDecorator.cs @@ -1,6 +1,4 @@ -using System.Diagnostics; - -namespace DecoratorPattern +namespace DecoratorPattern { // Note how we only override that which we actually need to override. public sealed class WithSpecialOfferDecorator : MemberDecoratorbase diff --git a/InterfaceSegregation_Shared/CabinetOpenAlarm/ChestOpenedAlarm.cs b/InterfaceSegregation_Shared/CabinetOpenAlarm/ChestOpenedAlarm.cs new file mode 100644 index 0000000..df1ab0b --- /dev/null +++ b/InterfaceSegregation_Shared/CabinetOpenAlarm/ChestOpenedAlarm.cs @@ -0,0 +1,12 @@ +using System.Diagnostics; + +namespace InterfaceSegregation +{ + public sealed class ChestOpenedAlarm + { + public void RaiseCabinetAlarm() + { + Debug.WriteLine("Raising the alarm, making lots of noise"); + } + } +} \ No newline at end of file diff --git a/InterfaceSegregation_Shared/InterfaceSegregation_Shared.projitems b/InterfaceSegregation_Shared/InterfaceSegregation_Shared.projitems index c4bc51b..3188d76 100644 --- a/InterfaceSegregation_Shared/InterfaceSegregation_Shared.projitems +++ b/InterfaceSegregation_Shared/InterfaceSegregation_Shared.projitems @@ -9,7 +9,7 @@ InterfaceSegregation_Shared - + \ No newline at end of file diff --git a/IntroToSOLIDwDesignPatterns.sln b/IntroToSOLIDwDesignPatterns.sln index 8717942..296cfd1 100644 --- a/IntroToSOLIDwDesignPatterns.sln +++ b/IntroToSOLIDwDesignPatterns.sln @@ -82,10 +82,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FacadePattern_challenge", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FacadePattern_challengedSolved", "DesignPatterns\StructuralPatterns\FacadePattern\FacadePattern_example\FacadePattern_challengedSolved\FacadePattern_challengedSolved.csproj", "{155264B4-51BF-43C1-B47D-FC0060B44F2D}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{F5CEF873-E025-49ED-B974-7BCAE4386875}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SolidPrinciples.Tests", "SolidPrinciples.Tests\SolidPrinciples.Tests.csproj", "{1464DF75-3D86-4292-9FC1-0B4C69D82A70}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SOLIDprinciples", "SOLIDprinciples", "{7F1351EE-3D08-40C5-9766-AFC31881C658}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OpenClosed", "OpenClosed", "{4EC2DD46-EDB4-4B27-80AC-141ECDE996B6}" @@ -120,8 +116,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DependencyInversion_Abstrac EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DependencyInversion_fludInterfacePattern", "SOLIDprinciples\DependencyInversion\DependencyInversion_fludInterfacePattern\DependencyInversion_fludInterfacePattern.csproj", "{D8338193-0BB8-4900-BC00-5B538BFEE930}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DesignPatterns.Tests", "DesignPatterns.Tests\DesignPatterns.Tests.csproj", "{1B25DBA8-68B0-496B-99F7-7900A4FB7FA5}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CompositePattern", "CompositePattern", "{6E37CB56-0591-4FB3-BBAF-7EC1C88C3BE9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompositePattern_concept", "DesignPatterns\StructuralPatterns\CompositePattern\CompositePattern_concept\CompositePattern_concept.csproj", "{13248987-BEB8-4C72-833E-2AF56B711087}" @@ -136,8 +130,6 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "DependencyInversion_Shared" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C86DFED1-2D31-4B7C-B291-CC0C819DFD11}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "InterfaceSegregation_Shared", "InterfaceSegregation_Shared\InterfaceSegregation_Shared.shproj", "{05CC6E4F-B96B-4E7A-8F08-52F1980B16D8}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SingleResponsibility", "SingleResponsibility", "{DEF0DC6A-7156-4578-AA8B-232066144988}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SingleResponsibility_BadDesign", "SOLIDprinciples\SingleResponsibility\SingleResponsibility_BadDesign\SingleResponsibility_BadDesign.csproj", "{6F2825ED-484D-4D65-9DF6-C038AC1ED939}" @@ -250,10 +242,6 @@ Global {155264B4-51BF-43C1-B47D-FC0060B44F2D}.Debug|Any CPU.Build.0 = Debug|Any CPU {155264B4-51BF-43C1-B47D-FC0060B44F2D}.Release|Any CPU.ActiveCfg = Release|Any CPU {155264B4-51BF-43C1-B47D-FC0060B44F2D}.Release|Any CPU.Build.0 = Release|Any CPU - {1464DF75-3D86-4292-9FC1-0B4C69D82A70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1464DF75-3D86-4292-9FC1-0B4C69D82A70}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1464DF75-3D86-4292-9FC1-0B4C69D82A70}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1464DF75-3D86-4292-9FC1-0B4C69D82A70}.Release|Any CPU.Build.0 = Release|Any CPU {7AF2AE3E-370B-4207-98C2-FB5C09EE4125}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7AF2AE3E-370B-4207-98C2-FB5C09EE4125}.Debug|Any CPU.Build.0 = Debug|Any CPU {7AF2AE3E-370B-4207-98C2-FB5C09EE4125}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -302,10 +290,6 @@ Global {D8338193-0BB8-4900-BC00-5B538BFEE930}.Debug|Any CPU.Build.0 = Debug|Any CPU {D8338193-0BB8-4900-BC00-5B538BFEE930}.Release|Any CPU.ActiveCfg = Release|Any CPU {D8338193-0BB8-4900-BC00-5B538BFEE930}.Release|Any CPU.Build.0 = Release|Any CPU - {1B25DBA8-68B0-496B-99F7-7900A4FB7FA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B25DBA8-68B0-496B-99F7-7900A4FB7FA5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B25DBA8-68B0-496B-99F7-7900A4FB7FA5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B25DBA8-68B0-496B-99F7-7900A4FB7FA5}.Release|Any CPU.Build.0 = Release|Any CPU {13248987-BEB8-4C72-833E-2AF56B711087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {13248987-BEB8-4C72-833E-2AF56B711087}.Debug|Any CPU.Build.0 = Debug|Any CPU {13248987-BEB8-4C72-833E-2AF56B711087}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -374,7 +358,6 @@ Global {55C9F033-A3EC-4A6C-B45A-096F3D850675} = {A3FE4252-D71B-48F0-947D-C2B40CE454F7} {C9D6B043-0497-4BE1-AA2E-D0F348C5821A} = {A3FE4252-D71B-48F0-947D-C2B40CE454F7} {155264B4-51BF-43C1-B47D-FC0060B44F2D} = {A3FE4252-D71B-48F0-947D-C2B40CE454F7} - {1464DF75-3D86-4292-9FC1-0B4C69D82A70} = {F5CEF873-E025-49ED-B974-7BCAE4386875} {4EC2DD46-EDB4-4B27-80AC-141ECDE996B6} = {7F1351EE-3D08-40C5-9766-AFC31881C658} {915FB00E-7812-4A14-A9E7-21F7267CB264} = {7F1351EE-3D08-40C5-9766-AFC31881C658} {0884B5EB-4B6E-42E4-9721-9A768C51D884} = {7F1351EE-3D08-40C5-9766-AFC31881C658} @@ -391,14 +374,12 @@ Global {EC71D90B-7A28-4B2B-A2D0-E4BC32598153} = {D21C7BEF-C20B-451A-9833-83192C420BD3} {A43EB3A3-192A-47F9-9F51-69D3215861C4} = {D21C7BEF-C20B-451A-9833-83192C420BD3} {D8338193-0BB8-4900-BC00-5B538BFEE930} = {D21C7BEF-C20B-451A-9833-83192C420BD3} - {1B25DBA8-68B0-496B-99F7-7900A4FB7FA5} = {F5CEF873-E025-49ED-B974-7BCAE4386875} {6E37CB56-0591-4FB3-BBAF-7EC1C88C3BE9} = {66F2519A-8343-4F99-9AAD-4D590CA61C1D} {13248987-BEB8-4C72-833E-2AF56B711087} = {6E37CB56-0591-4FB3-BBAF-7EC1C88C3BE9} {CE3FE3DC-F11D-4CF7-9FA6-081E376DD6C5} = {6E37CB56-0591-4FB3-BBAF-7EC1C88C3BE9} {1C01276E-D810-443E-9766-3AB8758B9ED6} = {CE3FE3DC-F11D-4CF7-9FA6-081E376DD6C5} {E8269DC1-511A-44FA-9F80-EEF258C2D9D8} = {915FB00E-7812-4A14-A9E7-21F7267CB264} {AFFCC124-8729-416A-A32B-E25D15A88869} = {D21C7BEF-C20B-451A-9833-83192C420BD3} - {05CC6E4F-B96B-4E7A-8F08-52F1980B16D8} = {0884B5EB-4B6E-42E4-9721-9A768C51D884} {DEF0DC6A-7156-4578-AA8B-232066144988} = {7F1351EE-3D08-40C5-9766-AFC31881C658} {6F2825ED-484D-4D65-9DF6-C038AC1ED939} = {DEF0DC6A-7156-4578-AA8B-232066144988} {BEA092C6-1984-486A-ACE0-6EC20E526728} = {DEF0DC6A-7156-4578-AA8B-232066144988} @@ -409,10 +390,8 @@ Global SolutionGuid = {DBD1FD10-66A6-4D20-BF13-62EC84D948FD} EndGlobalSection GlobalSection(SharedMSBuildProjectFiles) = preSolution - InterfaceSegregation_Shared\InterfaceSegregation_Shared.projitems*{05cc6e4f-b96b-4e7a-8f08-52f1980b16d8}*SharedItemsImports = 13 SingleResponsibility_Shared\SingleResponsibility_Shared.projitems*{6f2825ed-484d-4d65-9df6-c038ac1ed939}*SharedItemsImports = 5 DependencyInversion_Shared\DependencyInversion_Shared.projitems*{a43eb3a3-192a-47f9-9f51-69d3215861c4}*SharedItemsImports = 5 - InterfaceSegregation_Shared\InterfaceSegregation_Shared.projitems*{a9c9ed49-dd5a-4466-9f2a-79b5006ba940}*SharedItemsImports = 5 DependencyInversion_Shared\DependencyInversion_Shared.projitems*{affcc124-8729-416a-a32b-e25d15a88869}*SharedItemsImports = 13 SingleResponsibility_Shared\SingleResponsibility_Shared.projitems*{b82c448b-6b46-489f-b160-46dfb19fc5bb}*SharedItemsImports = 13 SingleResponsibility_Shared\SingleResponsibility_Shared.projitems*{bea092c6-1984-486a-ace0-6ec20e526728}*SharedItemsImports = 5 @@ -420,6 +399,5 @@ Global DependencyInversion_Shared\DependencyInversion_Shared.projitems*{d8338193-0bb8-4900-bc00-5b538bfee930}*SharedItemsImports = 5 DependencyInversion_Shared\DependencyInversion_Shared.projitems*{eb43956c-653e-45ab-aff8-1776596eb3d0}*SharedItemsImports = 5 DependencyInversion_Shared\DependencyInversion_Shared.projitems*{ec71d90b-7a28-4b2b-a2d0-e4bc32598153}*SharedItemsImports = 5 - InterfaceSegregation_Shared\InterfaceSegregation_Shared.projitems*{fa9f239d-697b-4946-b35b-c86d269c7f62}*SharedItemsImports = 5 EndGlobalSection EndGlobal diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/EnhancedAlarmFactory.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/EnhancedSpellsAlarmFactory.cs similarity index 59% rename from SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/EnhancedAlarmFactory.cs rename to SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/EnhancedSpellsAlarmFactory.cs index 3d58681..244c7dc 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/EnhancedAlarmFactory.cs +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/EnhancedSpellsAlarmFactory.cs @@ -2,14 +2,14 @@ namespace DependencyInversion_AbstractFactoryPattern.AlarmFactories { - public sealed class EnhancedAlarmFactory : IAlarmFactory + public sealed class EnhancedSpellsAlarmFactory : ISpellAlarmFactory { - public IAlarm CreateAudibleAlarm() + public ISpellAlarm CreateAudibleAlarm() { return new PersistentBeepAlarm(); } - public IAlarm CreateVisibleAlarm() + public ISpellAlarm CreateVisibleAlarm() { return new EnhancedDisplayAlarm(); } diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/IAlarmFactory.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/ISpellAlarmFactory.cs similarity index 69% rename from SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/IAlarmFactory.cs rename to SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/ISpellAlarmFactory.cs index 8bef59a..68c2f7d 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/IAlarmFactory.cs +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/ISpellAlarmFactory.cs @@ -6,10 +6,10 @@ namespace DependencyInversion_AbstractFactoryPattern.AlarmFactories /// Interface for creating an interface which creates objects - alarms, in this example - which /// share a common theme. /// - public interface IAlarmFactory + public interface ISpellAlarmFactory { - IAlarm CreateVisibleAlarm(); + ISpellAlarm CreateVisibleAlarm(); - IAlarm CreateAudibleAlarm(); + ISpellAlarm CreateAudibleAlarm(); } } \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/StandardAlarmFactory.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/StandardSpellsAlarmFactory.cs similarity index 58% rename from SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/StandardAlarmFactory.cs rename to SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/StandardSpellsAlarmFactory.cs index 9acb8da..5cccd36 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/StandardAlarmFactory.cs +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/AlarmFactories/StandardSpellsAlarmFactory.cs @@ -2,14 +2,14 @@ namespace DependencyInversion_AbstractFactoryPattern.AlarmFactories { - public sealed class StandardAlarmFactory : IAlarmFactory + public sealed class StandardSpellsAlarmFactory : ISpellAlarmFactory { - public IAlarm CreateAudibleAlarm() + public ISpellAlarm CreateAudibleAlarm() { return new WarningBellAlarm(); } - public IAlarm CreateVisibleAlarm() + public ISpellAlarm CreateVisibleAlarm() { return new DisplayAlarm(); } diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/Program.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/Program.cs index 5204c62..d7c2968 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/Program.cs +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/Program.cs @@ -1,7 +1,6 @@ using DependencyInversion; using DependencyInversion_AbstractFactoryPattern.AlarmFactories; using System.Collections.Generic; -using System.Diagnostics; namespace DependencyInversion_AbstractFactoryPattern { @@ -27,30 +26,32 @@ public static class Program /// public static void Main() { - // A collection of sensors must have alarms attached to them: - TemperatureSensor temperatureSensor1 = new TemperatureSensor("Temp1"); - TemperatureSensor temperatureSensor2 = new TemperatureSensor("Temp2"); - List sensorCollection = new() { temperatureSensor1, temperatureSensor2 }; + // A collection of spells must have alarms attached to them: + TemperatureSpell temperatureSpell1 = new TemperatureSpell("Temp1"); + TemperatureSpell temperatureSpell2 = new TemperatureSpell("Temp2"); + List spellsCollection = new() { temperatureSpell1, temperatureSpell2 }; // For standard alarms, we use a standard alarm factory: - IAlarmFactory standardAlarmFactory = new StandardAlarmFactory(); - sensorCollection.ForEach(sensor => + ISpellAlarmFactory standardAlarmFactory = new StandardSpellsAlarmFactory(); + spellsCollection.ForEach(sensor => { - sensor.AttachAlarm(standardAlarmFactory.CreateVisibleAlarm()); - sensor.AttachAlarm(standardAlarmFactory.CreateAudibleAlarm()); + sensor.AttachSpellAlarm(standardAlarmFactory.CreateVisibleAlarm()); + sensor.AttachSpellAlarm(standardAlarmFactory.CreateAudibleAlarm()); }); - SensorCabinet sensorCabinet = new(sensorCollection); - sensorCabinet.TestAlarms(); + + SpellBook spellBook = new(spellsCollection); + spellBook.TestAlarms(); // But for other scenarios, we might create 'enhanced' alarms via a different factory implementation: - IAlarmFactory enhancedAlarmFactory = new EnhancedAlarmFactory(); - sensorCollection.ForEach(sensor => + spellBook = new(spellsCollection); + ISpellAlarmFactory enhancedAlarmFactory = new EnhancedSpellsAlarmFactory(); + spellsCollection.ForEach(sensor => { - sensor.AttachAlarm(enhancedAlarmFactory.CreateVisibleAlarm()); - sensor.AttachAlarm(enhancedAlarmFactory.CreateAudibleAlarm()); + sensor.AttachSpellAlarm(enhancedAlarmFactory.CreateVisibleAlarm()); + sensor.AttachSpellAlarm(enhancedAlarmFactory.CreateAudibleAlarm()); }); - sensorCabinet = new(sensorCollection); - sensorCabinet.TestAlarms(); + spellBook = new(spellsCollection); + spellBook.TestAlarms(); } } } \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/SensorCabinet.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/SensorCabinet.cs deleted file mode 100644 index 272389d..0000000 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/SensorCabinet.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics; -using DependencyInversion; - -namespace DependencyInversion_AbstractFactoryPattern -{ - public sealed class SensorCabinet - { - private readonly List _sensors; - - public SensorCabinet(List sensors) - { - Debug.Assert(sensors != null, "list of sensors should be initialized at this point"); - _sensors = sensors; - } - - public void TestAlarms() - { - _sensors.ForEach(alarm => alarm.RaiseAlarms()); - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/SpellBook.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/SpellBook.cs new file mode 100644 index 0000000..dcb45fa --- /dev/null +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_AbstractFactoryPattern/SpellBook.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Diagnostics; +using DependencyInversion; + +namespace DependencyInversion_AbstractFactoryPattern +{ + public sealed class SpellBook + { + private readonly List _spells; + + public SpellBook(List spells) + { + _spells = spells; + } + + public void TestAlarms() + { + _spells.ForEach(alarm => alarm.RaiseSpellAlarms()); + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/Program.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/Program.cs index 00b24a3..1d64376 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/Program.cs +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/Program.cs @@ -1,25 +1,24 @@ -namespace DependencyInversion_BadDesign +namespace DependencyInversion { public static class Program { /// /// The dependency inversion principle states that a class should not declare its own dependencies - rather it should be provided with them. /// - /// Below, a poor example: A SensorCabinet declares a number of dependencies within its own confines, wherefore it becomes hard-coupled to these dependencies. + /// Below, a poor example: A declares a number of dependencies within its own confines, wherefore it becomes + /// hard-coupled to these dependencies. /// public static void Main() { // Initialization. Within these methods, there's a lot of creation logic going on. - SensorCabinet sensorCabinet = new(); - sensorCabinet.InitializeAlarms(); - sensorCabinet.InitializeSensors(); - sensorCabinet.AttachAlarmsToSensors(); + SpellBook spellBook = new(); + spellBook.InitializeSpells(); + spellBook.InitializeSpellAlarms(); + spellBook.AttachAlarmsToSpells(); - // At some point, we wish to write temperature sensor values to a log. - sensorCabinet.AttachLogger(); - sensorCabinet.WriteAllTemperatureSensorsDataToLog(); - - // Introducing Lab1 - introduce a better design. + // At some point, we wish to write status values to a log. + spellBook.AttachSpellLogger(); + spellBook.WriteAllTemperatureSpellsStatusToLogger(); } } } \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/SensorCabinet.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/SensorCabinet.cs deleted file mode 100644 index 25979e3..0000000 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/SensorCabinet.cs +++ /dev/null @@ -1,61 +0,0 @@ -using DependencyInversion; -using System.Collections.Generic; - -namespace DependencyInversion_BadDesign -{ - /// - /// A sensor cabinet, that holds a number of sensors. - /// - /// - /// This class does not honor the dependency inversion principle - lots of hard-wired dependencies. - /// - public sealed class SensorCabinet - { - public TemperatureSensor TemperatureSensor1 { get; private set; } - public TemperatureSensor TemperatureSensor2 { get; private set; } - public PressureSensor PressureSensor { get; private set; } - public DisplayAlarm DisplayAlarm { get; private set; } - public WarningBellAlarm WarningBellAlarm { get; private set; } - - public TemperatureSensorLogger TemperatureSensorLogger { get; private set; } - - public void InitializeSensors() - { - TemperatureSensor1 = new TemperatureSensor(sensorId: "Temp1"); - TemperatureSensor2 = new TemperatureSensor(sensorId: "Temp2"); - PressureSensor = new PressureSensor(); - } - - public void InitializeAlarms() - { - DisplayAlarm = new DisplayAlarm(); - WarningBellAlarm = new WarningBellAlarm(); - } - - public void AttachAlarmsToSensors() - { - TemperatureSensor1.AttachAlarm(DisplayAlarm); - - TemperatureSensor2.AttachAlarm(DisplayAlarm); - TemperatureSensor2.AttachAlarm(WarningBellAlarm); - - PressureSensor.AttachAlarm(DisplayAlarm); - PressureSensor.AttachAlarm(WarningBellAlarm); - } - - public void AttachLogger() - { - TemperatureSensorLogger = new TemperatureSensorLogger(new DiagnosticsLogger()); - } - - /// - /// Write sensor data for all temperature-sensors to the diagnostics-logger. - /// - public void WriteAllTemperatureSensorsDataToLog() - { - TemperatureSensorData sensorData1 = new(SensorId: TemperatureSensor1.Id, TemperatureSensor1.GetTemperature()); - TemperatureSensorData sensorData2 = new(SensorId: TemperatureSensor2.Id, TemperatureSensor2.GetTemperature()); - TemperatureSensorLogger.WriteAllTemperatureSensorsDataToLog(new List { sensorData1, sensorData2 }); - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/SpellBook.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/SpellBook.cs new file mode 100644 index 0000000..d099100 --- /dev/null +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_BadDesign/SpellBook.cs @@ -0,0 +1,60 @@ +using System.Collections.Generic; + +namespace DependencyInversion +{ + /// + /// A , that holds a number of spells. + /// + /// + /// This class does not honor the dependency inversion principle - lots of hard-wired dependencies. + /// + public sealed class SpellBook + { + private TemperatureSpell _temperatureSpell1 { get; set; } + private TemperatureSpell _temperatureSpell2 { get; set; } + private PressureSpell _pressureSpell { get; set; } + private DisplayAlarm _displayAlarm { get; set; } + private WarningBellAlarm _warningBellAlarm { get; set; } + + private TemperatureSpellLogger _temperatureSpellLogger { get; set; } + + public void InitializeSpells() + { + _temperatureSpell1 = new TemperatureSpell(spellId: "Temp1"); + _temperatureSpell2 = new TemperatureSpell(spellId: "Temp2"); + _pressureSpell = new PressureSpell(); + } + + public void InitializeSpellAlarms() + { + _displayAlarm = new DisplayAlarm(); + _warningBellAlarm = new WarningBellAlarm(); + } + + public void AttachAlarmsToSpells() + { + _temperatureSpell1.AttachSpellAlarm(_displayAlarm); + + _temperatureSpell2.AttachSpellAlarm(_displayAlarm); + _temperatureSpell2.AttachSpellAlarm(_warningBellAlarm); + + _pressureSpell.AttachSpellAlarm(_displayAlarm); + _pressureSpell.AttachSpellAlarm(_warningBellAlarm); + } + + public void AttachSpellLogger() + { + _temperatureSpellLogger = new TemperatureSpellLogger(new DiagnosticsLogger()); + } + + /// + /// Write data for all temperature-spells to the diagnostics-logger. + /// + public void WriteAllTemperatureSpellsStatusToLogger() + { + TemperatureSpellData spellData1 = new(SpellId: _temperatureSpell1.Id, _temperatureSpell1.GetTemperature()); + TemperatureSpellData spellData2 = new(SpellId: _temperatureSpell2.Id, _temperatureSpell2.GetTemperature()); + _temperatureSpellLogger.WriteAllTemperatureSpellsDataToLog(new List { spellData1, spellData2 }); + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SensorType.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SensorType.cs deleted file mode 100644 index 75167d5..0000000 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SensorType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace DependencyInversion_GoodDesign -{ - public enum SensorType - { - TemperatureSensor, - PressureSensor - } -} \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SensorConfiguration.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SpellConfiguration.cs similarity index 63% rename from SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SensorConfiguration.cs rename to SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SpellConfiguration.cs index cde730e..278b70e 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SensorConfiguration.cs +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SpellConfiguration.cs @@ -2,10 +2,10 @@ namespace DependencyInversion_GoodDesign.Configuration { - public class SensorConfiguration + public class SpellConfiguration { - public SensorType SensorType { get; set; } - public string SensorId { get; set; } + public SpellType SpellType { get; set; } + public string SpellId { get; set; } public AlarmConfiguration[] Alarms { get; set; } } diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SpellType.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SpellType.cs new file mode 100644 index 0000000..3604cbe --- /dev/null +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Configuration/SpellType.cs @@ -0,0 +1,8 @@ +namespace DependencyInversion_GoodDesign +{ + public enum SpellType + { + TemperatureSpell, + PressureSpell + } +} \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/DependencyInversion_GoodDesign.csproj b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/DependencyInversion_GoodDesign.csproj index 319a44e..7ba043a 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/DependencyInversion_GoodDesign.csproj +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/DependencyInversion_GoodDesign.csproj @@ -18,7 +18,7 @@ - + Always diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Program.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Program.cs index 9bcbfab..4b9d52e 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Program.cs +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/Program.cs @@ -23,49 +23,49 @@ public static partial class Program public static void Main(string[] args) { // Let's get the sensors from configuration. We could new them up, of course, if they don't lend themselves easily to configuration. - IConfigurationRoot config = new ConfigurationBuilder().AddJsonFile(@"sensorsAndAlarms.json").Build(); - List sensorsConfiguration = new(); - config.Bind("Sensors", sensorsConfiguration); - Debug.Assert(sensorsConfiguration.Any(), "No sensors initialized from config"); + IConfigurationRoot config = new ConfigurationBuilder().AddJsonFile(@"spellsAndAlarms.json").Build(); + List spellConfig = new(); + config.Bind("Spells", spellConfig); + Debug.Assert(spellConfig.Any(), "No spells initialized from config"); // Initialize the sensors based on their configuration data, and add them to the sensor-cabinet. - IEnumerable sensorCollection = InitializeSensors(sensorsConfiguration); - SensorCabinet sensorCabinet = new(sensorCollection); + IEnumerable spellsCollection = InitializeSpells(spellConfig); + SpellBook spellBook = new(spellsCollection); // At some point, we wish to write temperature sensor values to a log. // By removing the logger from the sensor-cabinet, we forego problems with the single-responsibility principle. - IEnumerable temperatureSensorData = sensorCabinet.GetAllTemperatureSensorsData(); + IEnumerable temperatureSpellsData = spellBook.GetAllTemperatureSpellsData(); - TemperatureSensorLogger temperatureSensorLogger = InitializeTemperatureSensorLogger(); - temperatureSensorLogger.WriteAllTemperatureSensorsDataToLog(temperatureSensorData); + TemperatureSpellLogger temperatureSensorLogger = InitializeTemperatureSpellsLogger(); + temperatureSensorLogger.WriteAllTemperatureSpellsDataToLog(temperatureSpellsData); } - private static IEnumerable InitializeSensors(List sensorConfigurations) + private static IEnumerable InitializeSpells(List spellConfigurations) { - foreach (SensorConfiguration sensorConfig in sensorConfigurations) + foreach (SpellConfiguration spellConfig in spellConfigurations) { // Initialize sensor - ISensor sensor = sensorConfig.SensorType switch + ISpell sensor = spellConfig.SpellType switch { - SensorType.TemperatureSensor => new TemperatureSensor(sensorConfig.SensorId), - SensorType.PressureSensor => new PressureSensor(), - _ => throw new ArgumentException($"Invalid {nameof(SensorType)} {sensorConfig.SensorType}") + SpellType.TemperatureSpell => new TemperatureSpell(spellConfig.SpellId), + SpellType.PressureSpell => new PressureSpell(), + _ => throw new ArgumentException($"Invalid {nameof(SpellType)} {spellConfig.SpellType}") }; // attach alarms - foreach (AlarmConfiguration alarmConfig in sensorConfig.Alarms) + foreach (AlarmConfiguration alarmConfig in spellConfig.Alarms) { - IAlarm alarm = InitializeAlarm(alarmConfig); - sensor.AttachAlarm(alarm); + ISpellAlarm alarm = InitializeAlarm(alarmConfig); + sensor.AttachSpellAlarm(alarm); } yield return sensor; } } - private static IAlarm InitializeAlarm(AlarmConfiguration alarmConfig) + private static ISpellAlarm InitializeAlarm(AlarmConfiguration alarmConfig) { - IAlarm alarm = alarmConfig.AlarmType switch + ISpellAlarm alarm = alarmConfig.AlarmType switch { AlarmType.DisplayAlarm => new DisplayAlarm(), AlarmType.WarningBellAlarm => new WarningBellAlarm(), @@ -74,10 +74,10 @@ private static IAlarm InitializeAlarm(AlarmConfiguration alarmConfig) return alarm; } - private static TemperatureSensorLogger InitializeTemperatureSensorLogger() + private static TemperatureSpellLogger InitializeTemperatureSpellsLogger() { DiagnosticsLogger diagnosticsLogger = new(); - TemperatureSensorLogger temperatureSensorLogger = new(diagnosticsLogger); + TemperatureSpellLogger temperatureSensorLogger = new(diagnosticsLogger); return temperatureSensorLogger; } } diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/SensorCabinet.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/SensorCabinet.cs deleted file mode 100644 index 8560643..0000000 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/SensorCabinet.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using DependencyInversion; - -namespace DependencyInversion_GoodDesign -{ - public sealed class SensorCabinet - { - private readonly IEnumerable _sensors; - - public SensorCabinet(IEnumerable sensors) - { - Debug.Assert(sensors != null, "list of sensors should be initialized at this point"); - _sensors = sensors; - } - - public IEnumerable GetAllTemperatureSensorsData() - { - IEnumerable temperatureSensors = _sensors.Where(sensor => sensor is TemperatureSensor).Cast(); - foreach (TemperatureSensor temperatureSensor in temperatureSensors) - { - TemperatureSensorData temperatureSensorData = GetTemperatureSensorData(temperatureSensor); - yield return temperatureSensorData; - }; - } - - private TemperatureSensorData GetTemperatureSensorData(TemperatureSensor temperatureSensor) - { - string sensorId = temperatureSensor.Id; - double temperature = temperatureSensor.GetTemperature(); - - Debug.Assert(!string.IsNullOrWhiteSpace(sensorId), "sensor-id should not be null or blank"); - Debug.Assert(temperature >= 0, "temperature should be >= 0"); - - return new TemperatureSensorData(sensorId, temperature); - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/SpellBook.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/SpellBook.cs new file mode 100644 index 0000000..a8b759e --- /dev/null +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/SpellBook.cs @@ -0,0 +1,38 @@ +using DependencyInversion; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace DependencyInversion_GoodDesign +{ + public sealed class SpellBook + { + private readonly IEnumerable _spells; + + public SpellBook(IEnumerable spells) + { + _spells = spells; + } + + public IEnumerable GetAllTemperatureSpellsData() + { + IEnumerable spells = _spells.Where(sensor => sensor is TemperatureSpell).Cast(); + foreach (TemperatureSpell spell in spells) + { + TemperatureSpellData temperatureSensorData = GetTemperatureSpellData(spell); + yield return temperatureSensorData; + }; + } + + private TemperatureSpellData GetTemperatureSpellData(TemperatureSpell temperatureSpell) + { + string spellId = temperatureSpell.Id; + double temperature = temperatureSpell.GetTemperature(); + + Debug.Assert(!string.IsNullOrWhiteSpace(spellId), $"{nameof(spellId)} should not be null or blank"); + Debug.Assert(temperature >= 0, $"{nameof(temperature)} should be >= 0"); + + return new TemperatureSpellData(spellId, temperature); + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/sensorsAndAlarms.json b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/spellsAndAlarms.json similarity index 69% rename from SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/sensorsAndAlarms.json rename to SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/spellsAndAlarms.json index 28da64b..a492daa 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/sensorsAndAlarms.json +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_GoodDesign/spellsAndAlarms.json @@ -1,8 +1,8 @@ { - "Sensors": [ + "Spells": [ { - "SensorType": "TemperatureSensor", - "SensorId": "Temp1", + "SpellType": "TemperatureSpell", + "SpellId": "Temp1", "Alarms": [ { "AlarmType": "DisplayAlarm" @@ -10,8 +10,8 @@ ] }, { - "SensorType": "TemperatureSensor", - "SensorId": "Temp2", + "SpellType": "TemperatureSpell", + "SpellId": "Temp2", "Alarms": [ { "AlarmType": "DisplayAlarm" @@ -22,7 +22,7 @@ ] }, { - "SensorType": "PressureSensor", + "SpellType": "PressureSpell", "Alarms": [ { "AlarmType": "DisplayAlarm" diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/Program.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/Program.cs index 6dce09f..eb15f32 100644 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/Program.cs +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/Program.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using DependencyInversion; +using DependencyInversion; namespace DependencyInversion_fluidInterfacePattern { @@ -13,15 +12,14 @@ public static partial class Program { public static void Main() { - SensorCabinet sensorCabinet = new SensorCabinet(/* No list of sensors here - we'll granularly add them via the fluid interface pattern instead */) - .WithSensor(new TemperatureSensor(sensorId: "Temp1")) - .WithSensor(new PressureSensor()) - .WithSensor(new TemperatureSensor(sensorId: "Temp2")) - .WithSensor(new TemperatureSensor(sensorId: "Temp3")) - .WithSensor(new TemperatureSensor(sensorId: "Temp4")) - .WithSensor(new PressureSensor()); - - sensorCabinet.WriteAllTemperatureSensorsDataToLog(new DiagnosticsLogger()); + SpellBook sensorCabinet = new SpellBook(/* No list of spells here - we'll granularly add them via the fluid interface pattern instead */) + .WithSpell(new TemperatureSpell(spellId: "Temp1")) + .WithSpell(new PressureSpell()) + .WithSpell(new TemperatureSpell(spellId: "Temp2")) + .WithSpell(new TemperatureSpell(spellId: "Temp3")) + .WithSpell(new TemperatureSpell(spellId: "Temp4")) + .WithSpell(new PressureSpell()); + } } } \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/SensorCabinet.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/SensorCabinet.cs deleted file mode 100644 index 3ec0448..0000000 --- a/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/SensorCabinet.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using DependencyInversion; - -namespace DependencyInversion_fluidInterfacePattern -{ - public sealed class SensorCabinet - { - private List _sensors = new (); - - public SensorCabinet WithSensor(ISensor sensor) - { - _sensors.Add(sensor); - return this; - } - - /// - /// Write sensor data for all temperature-sensors to the diagnostics-logger. - /// - public void WriteAllTemperatureSensorsDataToLog(DiagnosticsLogger diagnosticsLogger) - { - foreach (var sensor in _sensors.Where(sensor => sensor is TemperatureSensor).Cast()) - { - TemperatureSensorData temperatureSensorData = GetTemperatureSensorData(sensor); - diagnosticsLogger.WriteToLog(temperatureSensorData.ToString()); - } - } - - private TemperatureSensorData GetTemperatureSensorData(TemperatureSensor temperatureSensor) - { - string sensorId = temperatureSensor.Id; - double temperature = temperatureSensor.GetTemperature(); - - Debug.Assert(!string.IsNullOrWhiteSpace(sensorId), "sensor-id should not be null or blank"); - Debug.Assert(temperature >= 0, "temperature should be >= 0"); - - return new TemperatureSensorData(sensorId, temperature); - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/SpellBook.cs b/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/SpellBook.cs new file mode 100644 index 0000000..bbfcb46 --- /dev/null +++ b/SOLIDprinciples/DependencyInversion/DependencyInversion_fludInterfacePattern/SpellBook.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using DependencyInversion; + +namespace DependencyInversion_fluidInterfacePattern +{ + public sealed class SpellBook + { + private List _spells = new (); + + public SpellBook WithSpell(ISpell spell) + { + _spells.Add(spell); + return this; + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/CabinetAlarm.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/CabinetAlarm.cs new file mode 100644 index 0000000..b4720c3 --- /dev/null +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/CabinetAlarm.cs @@ -0,0 +1,12 @@ +using System.Diagnostics; + +namespace InterfaceSegregation_BadDesign +{ + public sealed class CabinetAlarm + { + public void RaiseCabinetAlarm() + { + Debug.WriteLine("Raising the alarm, making lots of noise"); + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/CabinetOpenedEventArgs.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/CabinetOpenedEventArgs.cs new file mode 100644 index 0000000..e03d6dc --- /dev/null +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/CabinetOpenedEventArgs.cs @@ -0,0 +1,9 @@ +using System; + +namespace InterfaceSegregation_BadDesign +{ + public sealed class CabinetOpenedEventArgs : EventArgs + { + public DateTime CabinetOpenTime; + } +} \ No newline at end of file diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/ISecretCabinet.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/ISecretCabinet.cs new file mode 100644 index 0000000..5794481 --- /dev/null +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/ISecretCabinet.cs @@ -0,0 +1,13 @@ +using System; + +namespace InterfaceSegregation_BadDesign +{ + public interface ISecretCabinet + { + event EventHandler CabinetOpenedEvent; + + void RaiseCabinetOpenAlarm(); + + void FireCabinetOpenedEvent(); + } +} \ No newline at end of file diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/ISecurityCabinet.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/ISecurityCabinet.cs deleted file mode 100644 index e548616..0000000 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/ISecurityCabinet.cs +++ /dev/null @@ -1,18 +0,0 @@ -using InterfaceSegregation; -using System; -using System.Collections.Generic; - -namespace InterfaceSegregation_BadDesign -{ - /// - /// The contract that all implementing security-cabinets must honor. - /// - public interface ISecurityCabinet - { - event EventHandler CabinetOpenedEvent; - - void RaiseCabinetOpenAlarm(); - - void FireCabinetOpenedEvent(); - } -} \ No newline at end of file diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/InterfaceSegregation_BadDesign.csproj b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/InterfaceSegregation_BadDesign.csproj index 210a9cc..b7889ef 100644 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/InterfaceSegregation_BadDesign.csproj +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/InterfaceSegregation_BadDesign.csproj @@ -13,5 +13,4 @@ - \ No newline at end of file diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/Program.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/Program.cs index dd17214..dbfbd9e 100644 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/Program.cs +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/Program.cs @@ -1,11 +1,8 @@ -using InterfaceSegregation; -using System.Diagnostics; - -namespace InterfaceSegregation_BadDesign +namespace InterfaceSegregation_BadDesign { /// /// The interface segregation principle states that no class should be forced to implement interface-methods it has not need for. - /// Below, a SensorCabinetWithoutAlarm() shouldn't have to implement ISensorCabinet-methods regarding alarms. + /// Below, a () shouldn't have to implement -methods regarding alarms. /// /// The principle mainly addresses the concern of bloat, in as much as it's a clear sign something that would usually be split into /// its own has not been. @@ -19,19 +16,19 @@ public sealed class Program { public static void Main() { - // For a 'regular' security-cabinet we attach a an event that raises an alarm when the open event occurs, - // because we have that method available to us via the ISecurityCabinet-interface. - SecurityCabinet securityCabinet = new SecurityCabinet(new CabinetAlarm()); - securityCabinet.CabinetOpenedEvent += CabinetOpenedEvent; - securityCabinet.FireCabinetOpenedEvent(); - securityCabinet.CabinetOpenedEvent -= CabinetOpenedEvent; + // For a 'regular' treasureChestFilledWithGold we attach a an event that raises an alarm when the open event occurs, + // because we have that method available to us via the -interface. + SecretCabinet treasureChestFilledWithGold = new (new CabinetAlarm()); + treasureChestFilledWithGold.CabinetOpenedEvent += CabinetOpenedEvent; + treasureChestFilledWithGold.FireCabinetOpenedEvent(); + treasureChestFilledWithGold.CabinetOpenedEvent -= CabinetOpenedEvent; - // But for a security-cabinet without alarm, we'll get an exception when we try to raise an alarm, - // since for this ISecurityCabinet we haven't implemented the 'RaiseCabinetOpenAlarm' method. - SensorCabinetWithoutAlarm securityCabinetWithoutAlarm = new SensorCabinetWithoutAlarm(); - securityCabinetWithoutAlarm.CabinetOpenedEvent += CabinetOpenedEvent; - securityCabinetWithoutAlarm.FireCabinetOpenedEvent(); - securityCabinetWithoutAlarm.CabinetOpenedEvent -= CabinetOpenedEvent; + // But for a fakeEmptyTreasureChest without alarm, we'll get an exception when we try to raise an alarm, + // since for this -implementation we haven't implemented the 'RaiseCabinetOpenAlarm' method. + SecretCabinetWithoutAlarm fakeEmptyTreasureChest = new(); + fakeEmptyTreasureChest.CabinetOpenedEvent += CabinetOpenedEvent; + fakeEmptyTreasureChest.FireCabinetOpenedEvent(); + fakeEmptyTreasureChest.CabinetOpenedEvent -= CabinetOpenedEvent; } private static void CabinetOpenedEvent(object sender, CabinetOpenedEventArgs cabinetOpenedEventArgs) @@ -39,7 +36,7 @@ private static void CabinetOpenedEvent(object sender, CabinetOpenedEventArgs cab System.DateTime openTime = cabinetOpenedEventArgs.CabinetOpenTime; if (openTime.DayOfWeek >= System.DayOfWeek.Sunday && openTime.DayOfWeek <= System.DayOfWeek.Saturday) { - ((ISecurityCabinet)sender).RaiseCabinetOpenAlarm(); + ((ISecretCabinet)sender).RaiseCabinetOpenAlarm(); } } } diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SecurityCabinet.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SecretCabinet.cs similarity index 60% rename from SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SecurityCabinet.cs rename to SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SecretCabinet.cs index 06764d8..215c4af 100644 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SecurityCabinet.cs +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SecretCabinet.cs @@ -1,21 +1,18 @@ -using InterfaceSegregation; -using System; -using System.Collections.Generic; +using System; using System.Diagnostics; -using System.Linq; namespace InterfaceSegregation_BadDesign { /// - /// A 'regular' security-cabinet. Includes an alarm, that fires when the + /// A 'regular' secret cabinet. Includes an alarm, that fires when the /// - public class SecurityCabinet : ISecurityCabinet + public class SecretCabinet : ISecretCabinet { private readonly CabinetAlarm _cabinetAlarm; public event EventHandler CabinetOpenedEvent; - public SecurityCabinet(CabinetAlarm cabinetAlarm) + public SecretCabinet(CabinetAlarm cabinetAlarm) { _cabinetAlarm = cabinetAlarm; } @@ -27,7 +24,6 @@ public void FireCabinetOpenedEvent() public void RaiseCabinetOpenAlarm() { - Debug.Assert(_cabinetAlarm != null, "Cabinet alarm not initialized"); _cabinetAlarm.RaiseCabinetAlarm(); } } diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SensorCabinetWithoutAlarm.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SecretCabinetWithoutAlarm.cs similarity index 84% rename from SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SensorCabinetWithoutAlarm.cs rename to SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SecretCabinetWithoutAlarm.cs index 2948f53..af1c986 100644 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SensorCabinetWithoutAlarm.cs +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_BadDesign/SecretCabinetWithoutAlarm.cs @@ -1,8 +1,5 @@ using InterfaceSegregation; using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; namespace InterfaceSegregation_BadDesign { @@ -11,7 +8,7 @@ namespace InterfaceSegregation_BadDesign /// with the interface-segregation principle - i.e. that we should not be having to implement a contract /// we don't fully need. /// - public sealed class SensorCabinetWithoutAlarm : ISecurityCabinet + public sealed class SecretCabinetWithoutAlarm : ISecretCabinet { public event EventHandler CabinetOpenedEvent; diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/CabinetAlarm.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/CabinetAlarm.cs new file mode 100644 index 0000000..ef12883 --- /dev/null +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/CabinetAlarm.cs @@ -0,0 +1,12 @@ +using System.Diagnostics; + +namespace InterfaceSegregation_GoodDesign +{ + public sealed class CabinetAlarm + { + public void RaiseCabinetAlarm() + { + Debug.WriteLine("Raising the alarm, making lots of noise"); + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/CabinetOpenedEventArgs.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/CabinetOpenedEventArgs.cs new file mode 100644 index 0000000..5e8b1d3 --- /dev/null +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/CabinetOpenedEventArgs.cs @@ -0,0 +1,9 @@ +using System; + +namespace InterfaceSegregation_GoodDesign +{ + public sealed class CabinetOpenedEventArgs : EventArgs + { + public DateTime CabinetOpenTime; + } +} \ No newline at end of file diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/ICabinetOpening.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/ICabinetOpening.cs index b6207f8..ed12915 100644 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/ICabinetOpening.cs +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/ICabinetOpening.cs @@ -1,5 +1,4 @@ -using InterfaceSegregation; -using System; +using System; namespace InterfaceSegregation_GoodDesign { diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/InterfaceSegregation_GoodDesign.csproj b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/InterfaceSegregation_GoodDesign.csproj index 1de3449..68107a9 100644 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/InterfaceSegregation_GoodDesign.csproj +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/InterfaceSegregation_GoodDesign.csproj @@ -13,5 +13,4 @@ - \ No newline at end of file diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/Program.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/Program.cs index 94e7acd..088f8c3 100644 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/Program.cs +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/Program.cs @@ -1,6 +1,4 @@ -using InterfaceSegregation; -using System; -using System.Diagnostics; +using System; namespace InterfaceSegregation_GoodDesign { @@ -15,16 +13,16 @@ public sealed class Program public static void Main() { // For a 'regular' security-cabinet we attach a an event when the open event occurs, - SecurityCabinet securityCabinet = new SecurityCabinet(new CabinetAlarm()); - securityCabinet.CabinetOpenedEvent += CabinetOpenedEvent; - securityCabinet.FireCabinetOpenedEvent(); - securityCabinet.CabinetOpenedEvent -= CabinetOpenedEvent; + SecretCabinet treasureChestFilledWithGold = new SecretCabinet(new CabinetAlarm()); + treasureChestFilledWithGold.CabinetOpenedEvent += CabinetOpenedEvent; + treasureChestFilledWithGold.FireCabinetOpenedEvent(); + treasureChestFilledWithGold.CabinetOpenedEvent -= CabinetOpenedEvent; // and the same for the cabinet without an alarm. - SensorCabinetWithoutAlarm securityCabinetWithoutAlarm = new SensorCabinetWithoutAlarm(); - securityCabinetWithoutAlarm.CabinetOpenedEvent += CabinetOpenedEvent; - securityCabinetWithoutAlarm.FireCabinetOpenedEvent(); - securityCabinetWithoutAlarm.CabinetOpenedEvent -= CabinetOpenedEvent; + SecretCabinetWithoutAlarm fakeEmptyTreasureChest = new SecretCabinetWithoutAlarm(); + fakeEmptyTreasureChest.CabinetOpenedEvent += CabinetOpenedEvent; + fakeEmptyTreasureChest.FireCabinetOpenedEvent(); + fakeEmptyTreasureChest.CabinetOpenedEvent -= CabinetOpenedEvent; } /// diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SecurityCabinet.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SecretCabinet.cs similarity index 64% rename from SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SecurityCabinet.cs rename to SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SecretCabinet.cs index 6dd7dac..2a36549 100644 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SecurityCabinet.cs +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SecretCabinet.cs @@ -1,21 +1,19 @@ -using InterfaceSegregation; -using System; -using System.Diagnostics; +using System; namespace InterfaceSegregation_GoodDesign { /// - /// A 'regular' security-cabinet. Includes an alarm. Implements multiple interfaces. + /// A 'regular' secret cabinet. Includes an alarm. Implements multiple interfaces. /// /// /// - public class SecurityCabinet : ICabinetOpening, ICabinetAlarming + public class SecretCabinet : ICabinetOpening, ICabinetAlarming { private readonly CabinetAlarm _cabinetAlarm; public event EventHandler CabinetOpenedEvent; - public SecurityCabinet(CabinetAlarm cabinetAlarm) + public SecretCabinet(CabinetAlarm cabinetAlarm) { _cabinetAlarm = cabinetAlarm; } @@ -27,7 +25,6 @@ public void FireCabinetOpenedEvent() public void RaiseCabinetOpenAlarm() { - Debug.Assert(_cabinetAlarm != null, "Cabinet alarm not initialized"); _cabinetAlarm.RaiseCabinetAlarm(); } } diff --git a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SensorCabinetWithoutAlarm.cs b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SecretCabinetWithoutAlarm.cs similarity index 73% rename from SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SensorCabinetWithoutAlarm.cs rename to SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SecretCabinetWithoutAlarm.cs index 9d0137a..e26ac9e 100644 --- a/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SensorCabinetWithoutAlarm.cs +++ b/SOLIDprinciples/InterfaceSegregation/InterfaceSegregation_GoodDesign/SecretCabinetWithoutAlarm.cs @@ -1,10 +1,8 @@ -using InterfaceSegregation; -using InterfaceSegregation_GoodDesign; -using System; +using System; namespace InterfaceSegregation_GoodDesign { - public sealed class SensorCabinetWithoutAlarm : ICabinetOpening + public sealed class SecretCabinetWithoutAlarm : ICabinetOpening { public event EventHandler CabinetOpenedEvent; diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/IArmorHitAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/IArmorHitAlarm.cs new file mode 100644 index 0000000..7a26ee9 --- /dev/null +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/IArmorHitAlarm.cs @@ -0,0 +1,9 @@ +namespace LiskovSubstitution_BadDesign +{ + public interface IArmorHitAlarm + { + bool HasArmorDroppedBelowThreshold(int currentArmorDefensePoints); + + void RaiseAlarm(); + } +} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/IVoltageAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/IVoltageAlarm.cs deleted file mode 100644 index 09b882a..0000000 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/IVoltageAlarm.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace LiskovSubstitution_BadDesign -{ - public interface IVoltageAlarm - { - int NumberOfAlarmsRaised { get; } - - double VoltageAlarmThreshold { get; } - - bool HasVoltageDroppedBelowThreshold(double currentVoltageLevel); - - void RaiseAlarm(); - } -} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/MacheteHitAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/MacheteHitAlarm.cs new file mode 100644 index 0000000..8734208 --- /dev/null +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/MacheteHitAlarm.cs @@ -0,0 +1,47 @@ +using System; +using System.Diagnostics; + +namespace LiskovSubstitution_BadDesign +{ + public sealed class MacheteHitAlarm : IArmorHitAlarm + { + private const int NUMBER_OF_ALARM_REPETITIONS = 3; + + private int _numberOfAlarmsRaised = 0; + private readonly int _armorAlarmThreshold; + + public MacheteHitAlarm(int alarmThreshold) + { + _armorAlarmThreshold = alarmThreshold; + } + + public bool HasArmorDroppedBelowThreshold(int currentArmorDefensePoints) + { + // Liskov Substitution violation - altered pre-condition! This class breaks the intent of the contract and the other + // implementations of the IArmorHitAlarm interface. + bool isNight = DateTime.UtcNow.TimeOfDay.Hours > 22 && DateTime.UtcNow.TimeOfDay.Hours < 6; + if (isNight) + { + return true; // machete hits at night instantly indicates the armor has dropped below the threshold. + } + else + { + bool hasArmorDefenseDroppedBelowMinimum = currentArmorDefensePoints < _armorAlarmThreshold; + return hasArmorDefenseDroppedBelowMinimum; + } + } + + public void RaiseAlarm() + { + // Liskov Substitution violation - difference in the meaningfulness of the function's implementation. The other + // interface-implementations don't deal with 'NUMBER_OF_ALARM_REPETITIONS'. + for (int i = 0; i < NUMBER_OF_ALARM_REPETITIONS; i++) + { + _numberOfAlarmsRaised += 1; + Debug.WriteLine($"Alarm raised {_numberOfAlarmsRaised} times."); + } + } + + + } +} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/NewVoltageAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/NewVoltageAlarm.cs deleted file mode 100644 index 9bf4bb2..0000000 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/NewVoltageAlarm.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Diagnostics; - -namespace LiskovSubstitution_BadDesign -{ - public sealed class NewVoltageAlarm : IVoltageAlarm - { - private const int NUMBER_OF_ALARM_REPETITIONS = 3; - public int NumberOfAlarmsRaised { get; private set; } - - public double VoltageAlarmThreshold { get; private set; } - - public NewVoltageAlarm(double voltageAlarmThreshold) - { - NumberOfAlarmsRaised = 0; - VoltageAlarmThreshold = voltageAlarmThreshold; - } - - public bool HasVoltageDroppedBelowThreshold(double currentVoltageLevel) - { - // violation - strenghed pre-condition!! - Debug.Assert(currentVoltageLevel < 5); // our new sensor can only take as much... - - bool hasVoltageDroppedBelowMinimum = currentVoltageLevel < VoltageAlarmThreshold; - return hasVoltageDroppedBelowMinimum; - } - - public void RaiseAlarm() - { - // violation - difference in the meaningfullness of the function's implementation. StandardVoltageAlarm doesn't deal in repititions. - for (int i = 0; i < NUMBER_OF_ALARM_REPETITIONS; i++) - { - NumberOfAlarmsRaised += 1; - Debug.WriteLine($"Alarm raised {NumberOfAlarmsRaised} times."); - } - } - - public void ResetNumberOfAlarmsRaised() - { - NumberOfAlarmsRaised = 0; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/PlayerArmor.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/PlayerArmor.cs new file mode 100644 index 0000000..4da4ab3 --- /dev/null +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/PlayerArmor.cs @@ -0,0 +1,32 @@ +namespace LiskovSubstitution_BadDesign +{ + public sealed class PlayerArmor + { + private IArmorHitAlarm _armorHitAlarm; + private int _currentArmorDefensePoints; + + public PlayerArmor(int initialArmorDefensePoints) + { + _currentArmorDefensePoints = initialArmorDefensePoints; + } + + public void SetArmorHitAlarm(IArmorHitAlarm armorHitAlarm) + { + _armorHitAlarm = armorHitAlarm; + } + + public void SubtractDefensePoints(int defensePointsToSubtract) + { + _currentArmorDefensePoints -= defensePointsToSubtract; + } + + public void RaiseAlarmIfArmorDefenseBelowThreshold() + { + bool hasVoltageDroppedBelowAcceptableLevel = _armorHitAlarm.HasArmorDroppedBelowThreshold(_currentArmorDefensePoints); // knows only about the interface. Any IArmorHitAlarm is supported. + if (hasVoltageDroppedBelowAcceptableLevel) + { + _armorHitAlarm.RaiseAlarm(); + } + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/Program.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/Program.cs index c29f9f2..9e42a75 100644 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/Program.cs +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/Program.cs @@ -1,16 +1,39 @@ -namespace LiskovSubstitution_BadDesign +using System; + +namespace LiskovSubstitution_BadDesign { + /// + /// The Liskov Substitution Principle states that an object with a certain interface should be replaceable by a different object that implements + /// that same interface while retaining all the correctness of the original intent. That means that not only does the interface have to + /// have exactly the same types, but the behavior has to remain correct as well. + /// + /// The main issue with breaking the principle comes from unrealized or faulty expectations. We're led to adopt and believe + /// one kind of behavior, but trust is breached and insecurities arise (and technical debt accrues) when it turns + /// out we can't count on what we're been told. + /// + /// + /// Barbara Liskov is an American computer scientist. + /// public sealed class Program { - // The Liskov Substitution Principle states that an object with a certain interface can be replaced by a different object that implements that same interface while retaining all the correctness of the original program. That means that not only does the interface have to have exactly the same types, but the behavior has to remain correct as well. - - // A VoltageSensor-class reads a sensor-voltage and raises an alarm if the voltage dips below a given threshold. This works well for a Standard-voltage alarm, but a newly introduced NewVoltageAlarm() implementation introduces different requirements and thus breaks the Liskov substitution principle. + /// + /// A subtracts a number of defense-points and raises an if the armor-level + /// dips below a given threshold. This works well for a standard implementation, but a newly introduced + /// introduces different requirements and thus breaks with the Liskov Substitution principle. + /// public static void Main() { - VoltageSensor voltageSensor = new(); - voltageSensor.SetVoltageAlarm(new StandardVoltageAlarm(3.3d)); - voltageSensor.ReadCurrentSensorVoltage(); - voltageSensor.RaiseAlarmIfVoltageBelowMinimum(); + PlayerArmor playerArmor = new(initialArmorDefensePoints: 100); + + IArmorHitAlarm swordHitAlarm = new SwordHitAlarm(alarmThreshold: 3); + playerArmor.SetArmorHitAlarm(swordHitAlarm); + playerArmor.SubtractDefensePoints(new Random().Next()); + playerArmor.RaiseAlarmIfArmorDefenseBelowThreshold(); + + IArmorHitAlarm macheteHitAlarm = new MacheteHitAlarm(alarmThreshold: 6); + playerArmor.SetArmorHitAlarm(macheteHitAlarm); + playerArmor.SubtractDefensePoints(new Random().Next()); + playerArmor.RaiseAlarmIfArmorDefenseBelowThreshold(); } } } \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/StandardVoltageAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/StandardVoltageAlarm.cs deleted file mode 100644 index 83e5026..0000000 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/StandardVoltageAlarm.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Diagnostics; - -namespace LiskovSubstitution_BadDesign -{ - public sealed class StandardVoltageAlarm : IVoltageAlarm - { - public int NumberOfAlarmsRaised { get; private set; } - - public double VoltageAlarmThreshold { get; private set; } - - public StandardVoltageAlarm(double alarmVoltageThreshold) - { - NumberOfAlarmsRaised = 0; - VoltageAlarmThreshold = alarmVoltageThreshold; - } - - public bool HasVoltageDroppedBelowThreshold(double currentVoltageLevel) - { - bool hasVoltageDroppedBelowMinimum = currentVoltageLevel < VoltageAlarmThreshold; - return hasVoltageDroppedBelowMinimum; - } - - public void RaiseAlarm() - { - NumberOfAlarmsRaised += 1; - Debug.WriteLine($"Alarm raised {NumberOfAlarmsRaised} times."); - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/SwordHitAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/SwordHitAlarm.cs new file mode 100644 index 0000000..8c169d4 --- /dev/null +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/SwordHitAlarm.cs @@ -0,0 +1,25 @@ +using System.Diagnostics; + +namespace LiskovSubstitution_BadDesign +{ + public sealed class SwordHitAlarm : IArmorHitAlarm + { + private readonly int _armorAlarmThreshold; + + public SwordHitAlarm(int alarmThreshold) + { + _armorAlarmThreshold = alarmThreshold; + } + + public bool HasArmorDroppedBelowThreshold(int currentArmorDefensePoints) + { + bool hasArmorDefenseDroppedBelowMinimum = currentArmorDefensePoints < _armorAlarmThreshold; + return hasArmorDefenseDroppedBelowMinimum; + } + + public void RaiseAlarm() + { + Debug.WriteLine($"{nameof(SwordHitAlarm)} raised."); + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/VoltageSensor.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/VoltageSensor.cs deleted file mode 100644 index aeaccbd..0000000 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_ BadDesign/VoltageSensor.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Diagnostics; - -namespace LiskovSubstitution_BadDesign -{ - public sealed class VoltageSensor - { - private IVoltageAlarm _voltageAlarm; - private double _currentSensorVoltage; - - public double CurrentSensorVoltage { get => _currentSensorVoltage; set => _currentSensorVoltage = value; } - - public VoltageSensor() - { - } - - public void SetVoltageAlarm(IVoltageAlarm alarm) - { - _voltageAlarm = alarm; - } - - public void ReadCurrentSensorVoltage() - { - Random someRandomFakeSensorVoltage = new(); - _currentSensorVoltage = 3 + someRandomFakeSensorVoltage.NextDouble(); - } - - public void RaiseAlarmIfVoltageBelowMinimum() - { - Debug.Assert(_voltageAlarm != null, "Voltage-alarm should be initialized at this point."); - bool hasVoltageDroppedBelowAcceptableLevel = _voltageAlarm.HasVoltageDroppedBelowThreshold(_currentSensorVoltage); // knows only about the interface. Any IVoltageAlarm is supported. - - if (hasVoltageDroppedBelowAcceptableLevel) - { - // glaring violation - hacks a specific path for a known implementation. Also violates OpenClosed-principle, we would have to update code with new alarm-implementations. - if (_voltageAlarm is NewVoltageAlarm) - { - _voltageAlarm.RaiseAlarm(); - (_voltageAlarm as NewVoltageAlarm).ResetNumberOfAlarmsRaised(); // This is custom for the specific implementation. - } - else - { - _voltageAlarm.RaiseAlarm(); - } - } - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/HitAlarmBase.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/HitAlarmBase.cs new file mode 100644 index 0000000..ab9610b --- /dev/null +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/HitAlarmBase.cs @@ -0,0 +1,55 @@ +using System.Diagnostics; + +namespace LiskovSubstitution_GoodDesignWithTemplatePattern +{ + /// + /// In this abstract class we encompass the range of functionality of all the + /// implementations of the interface. + /// + public abstract class HitAlarmBase : IArmorHitAlarm + { + private readonly int _numberOfAlarmRepetitions = 3; + private readonly int _armorAlarmThreshold; + private int _numberOfAlarmsRaised = 0; + + public HitAlarmBase(int numberOfAlarmRepetitions, int alarmThreshold) + { + _numberOfAlarmRepetitions = numberOfAlarmRepetitions; + _armorAlarmThreshold = alarmThreshold; + } + + public bool HasArmorDroppedBelowThreshold(int currentArmorDefensePoints) + { + bool alarmIsOverridden = HasArmorDroppedBelowThresholdOverride() is true; + if (alarmIsOverridden) + { + return true; + } + else + { + bool hasArmorDefenseDroppedBelowMinimum = currentArmorDefensePoints < _armorAlarmThreshold; + return hasArmorDefenseDroppedBelowMinimum; + } + } + + /// + /// Template method - the overrides this and thus aligns itself with + /// the Liskov principle. + /// + /// + public virtual bool HasArmorDroppedBelowThresholdOverride() + { + return false; + } + + public void RaiseAlarm() + { + // Liskov violation - difference in the meaningfulness of the function's implementation. The other interface-implementations don't deal with repetitions. + for (int i = 0; i < _numberOfAlarmRepetitions; i++) + { + _numberOfAlarmsRaised += 1; + Debug.WriteLine($"Alarm raised {_numberOfAlarmsRaised} times."); + } + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/IArmorHitAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/IArmorHitAlarm.cs new file mode 100644 index 0000000..bf0796a --- /dev/null +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/IArmorHitAlarm.cs @@ -0,0 +1,9 @@ +namespace LiskovSubstitution_GoodDesignWithTemplatePattern +{ + public interface IArmorHitAlarm + { + bool HasArmorDroppedBelowThreshold(int currentArmorDefensePoints); + + void RaiseAlarm(); + } +} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/IVoltageAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/IVoltageAlarm.cs deleted file mode 100644 index 45befa3..0000000 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/IVoltageAlarm.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace LiskovSubstitution_GoodDesign -{ - public interface IVoltageAlarm - { - int NumberOfAlarmsRaised { get; } - - double VoltageAlarmThreshold { get; } - - bool HasVoltageDroppedBelowThreshold(double voltageLevel); - - void RaiseAlarm(); - } -} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/MacheteHitAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/MacheteHitAlarm.cs new file mode 100644 index 0000000..9c25dab --- /dev/null +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/MacheteHitAlarm.cs @@ -0,0 +1,19 @@ +using System; +using System.Diagnostics; + +namespace LiskovSubstitution_GoodDesignWithTemplatePattern +{ + public sealed class MacheteHitAlarm : HitAlarmBase + { + public MacheteHitAlarm(int alarmThreshold) : + base(numberOfAlarmRepetitions: 3, alarmThreshold) + { + } + + public override bool HasArmorDroppedBelowThresholdOverride() + { + bool isNight = DateTime.UtcNow.TimeOfDay.Hours > 22 && DateTime.UtcNow.TimeOfDay.Hours < 6; + return isNight; + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/NewVoltageAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/NewVoltageAlarm.cs deleted file mode 100644 index b1f04f2..0000000 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/NewVoltageAlarm.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace LiskovSubstitution_GoodDesign - -{ - public sealed class NewVoltageAlarm : VoltageAlarmBase - { - private const int NUMBER_OF_ALARM_REPETITIONS = 3; - - public NewVoltageAlarm(double alarmMinimumVoltageValue) : base(alarmMinimumVoltageValue) - { - } - - public override int GetNumberOfAlarmRepetitions() - { - return NUMBER_OF_ALARM_REPETITIONS; - } - - public override double GetMaximumAllowableVoltageLevel() - { - return 5d; // 5v max - } - - public override bool ShouldResetNumberOfAlarmsRaised() - { - return true; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/PlayerArmor.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/PlayerArmor.cs new file mode 100644 index 0000000..0642cee --- /dev/null +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/PlayerArmor.cs @@ -0,0 +1,32 @@ +namespace LiskovSubstitution_GoodDesignWithTemplatePattern +{ + public sealed class PlayerArmor + { + private IArmorHitAlarm _armorHitAlarm; + private int _currentArmorDefensePoints; + + public PlayerArmor(int initialArmorDefensePoints) + { + _currentArmorDefensePoints = initialArmorDefensePoints; + } + + public void SetArmorHitAlarm(IArmorHitAlarm armorHitAlarm) + { + _armorHitAlarm = armorHitAlarm; + } + + public void SubtractDefensePoints(int defensePointsToSubtract) + { + _currentArmorDefensePoints -= defensePointsToSubtract; + } + + public void RaiseAlarmIfArmorDefenseBelowThreshold() + { + bool hasVoltageDroppedBelowAcceptableLevel = _armorHitAlarm.HasArmorDroppedBelowThreshold(_currentArmorDefensePoints); // knows only about the interface. Any IArmorHitAlarm is supported. + if (hasVoltageDroppedBelowAcceptableLevel) + { + _armorHitAlarm.RaiseAlarm(); + } + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/Program.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/Program.cs index b5f6968..08252cc 100644 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/Program.cs +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/Program.cs @@ -1,20 +1,29 @@ -namespace LiskovSubstitution_GoodDesign +using System; + +namespace LiskovSubstitution_GoodDesignWithTemplatePattern { + /// + /// The Liskov Substitution principle, in comparison to the other principles in the SOLID acronym, doesn't lend + /// itself well to code-smells detection. Best we can do is to foster the discipline and weed it out as we see it. + /// In the -class we've encompassed the combined functionality of the + /// implementations. In this way we can ensure the different implementations are substitutable with each other. + /// + /// - great phone-realization of the principle. public sealed class Program { - // A 'good example' on Liskov substitution is simply to not allow our sub-classes to differ in the meaning of their - // implementations. I.e. no explicit paths for certain sub-types, no strenghtening of conditions etc. - // If a need to break away from limitations of the originals class arises, - // we can add the required functionality to that original class. - - // By introducing an abstract base-class, which takes into consideration the diverse implementations, - // we can ensure sub-class compatibility. Given additional requirements - for example, we only need to modify the base-class, - // single point of maintainability. public static void Main() { - VoltageSensor voltageSensor = new(); - voltageSensor.ReadCurrentSensorVoltage(); - voltageSensor.RaiseAlarmIfVoltageBelowThreshold(); + PlayerArmor playerArmor = new(initialArmorDefensePoints: 100); + + HitAlarmBase swordHitAlarm = new SwordHitAlarm(alarmThreshold: 3); + playerArmor.SetArmorHitAlarm(swordHitAlarm); + playerArmor.SubtractDefensePoints(new Random().Next()); + playerArmor.RaiseAlarmIfArmorDefenseBelowThreshold(); + + HitAlarmBase macheteHitAlarm = new MacheteHitAlarm(alarmThreshold: 6); + playerArmor.SetArmorHitAlarm(macheteHitAlarm); + playerArmor.SubtractDefensePoints(new Random().Next()); + playerArmor.RaiseAlarmIfArmorDefenseBelowThreshold(); } } } \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/StandardVoltageAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/StandardVoltageAlarm.cs deleted file mode 100644 index aa10098..0000000 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/StandardVoltageAlarm.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace LiskovSubstitution_GoodDesign -{ - public sealed class StandardVoltageAlarm : VoltageAlarmBase - { - public StandardVoltageAlarm(double alarmVoltageThreshold) : base(alarmVoltageThreshold) - { - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/SwordHitAlarm.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/SwordHitAlarm.cs new file mode 100644 index 0000000..a08081a --- /dev/null +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/SwordHitAlarm.cs @@ -0,0 +1,12 @@ +using System; + +namespace LiskovSubstitution_GoodDesignWithTemplatePattern +{ + public sealed class SwordHitAlarm : HitAlarmBase + { + public SwordHitAlarm(int alarmThreshold) : + base(numberOfAlarmRepetitions: 0, alarmThreshold) + { + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/VoltageAlarmBase.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/VoltageAlarmBase.cs deleted file mode 100644 index 77cd4b4..0000000 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/VoltageAlarmBase.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System.Diagnostics; - -namespace LiskovSubstitution_GoodDesign -{ - // To ensure compatibility among sub-classes, we can introduce an abstract base-class that allows for corresponding behaviour throughout our subclassings. I.e. this base-class compiles the combined functionality of the various IVoltageAlarm implementations we have (so far). - //? Note the use of the template-pattern, to achieve compatability. - public abstract class VoltageAlarmBase : IVoltageAlarm - { - private const int DEFAULT_NUMBER_OF_ALARM_ITERATIONS = 1; - private const double DEFAULT_MAX_ALLOWED_VOLTAGE_LEVEL = double.MaxValue; - private const bool DEFAULT_SHOULD_RESET_NUMBER_OF_ALARMS = false; - - public int NumberOfAlarmsRaised { get; private set; } - - public double VoltageAlarmThreshold { get; private set; } - - public VoltageAlarmBase(double alarmVoltageThreshold) - { - NumberOfAlarmsRaised = 0; - VoltageAlarmThreshold = alarmVoltageThreshold; - } - - public bool HasVoltageDroppedBelowThreshold(double currentVoltageLevel) // 'Template method' - { - // The NewVoltageAlarm requires a max voltage of 5, but our StandardVoltageAlarm doesn't have this requirement. We can again use the template pattern to accomodate, defaulting to double.maxvalue. - double maximumAllowableVoltageLevel = GetMaximumAllowableVoltageLevel(); - Debug.Assert(currentVoltageLevel < maximumAllowableVoltageLevel); - - bool hasVoltageDroppedBelowThreshold = currentVoltageLevel < VoltageAlarmThreshold; - return hasVoltageDroppedBelowThreshold; - } - - public virtual double GetMaximumAllowableVoltageLevel() - { - return DEFAULT_MAX_ALLOWED_VOLTAGE_LEVEL; - } - - public void RaiseAlarm() // 'Template method'. Note we adopted the NewVoltageAlarm's repetition-scheme here, but defaults it to '1' to accomodate the StandardVoltageAlarm. - { - int numberOfAlarmRepetitions = GetNumberOfAlarmRepetitions(); - for (int i = 0; i < numberOfAlarmRepetitions; i++) - { - NumberOfAlarmsRaised += 1; - Debug.WriteLine($"Alarm raised {NumberOfAlarmsRaised} times."); - } - - if (ShouldResetNumberOfAlarmsRaised()) - { - ResetNumberOfAlarmsRaised(); - } - } - - public virtual bool ShouldResetNumberOfAlarmsRaised() // 'Hook' method - { - return DEFAULT_SHOULD_RESET_NUMBER_OF_ALARMS; - } - - public virtual int GetNumberOfAlarmRepetitions() - { - return DEFAULT_NUMBER_OF_ALARM_ITERATIONS; - } - - public void ResetNumberOfAlarmsRaised() - { - NumberOfAlarmsRaised = 0; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/VoltageSensor.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/VoltageSensor.cs deleted file mode 100644 index 52ef432..0000000 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_GoodDesignWithTemplatePattern/VoltageSensor.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; - -namespace LiskovSubstitution_GoodDesign -{ - public sealed class VoltageSensor - { - private readonly IVoltageAlarm _voltageAlarm; - private double _currentSensorVoltage; - - public VoltageSensor() - { - _voltageAlarm = new StandardVoltageAlarm(3.3d); // now truly interchangable w. NewVoltageAlarm. - } - - public void ReadCurrentSensorVoltage() - { - Random rnd = new(); - _currentSensorVoltage = 3 + rnd.NextDouble(); - } - - public void RaiseAlarmIfVoltageBelowThreshold() - { - bool hasVoltageDroppedBelowThreshold = _voltageAlarm.HasVoltageDroppedBelowThreshold(_currentSensorVoltage); // knows only about the interface. Any IVoltageAlarm is supported. - - if (hasVoltageDroppedBelowThreshold) - { - _voltageAlarm.RaiseAlarm(); - - /*# - // glaring violation - hacks a specific path for a known implementation. Also violates OpenClosed-principle. - if (_voltageAlarm is NewVoltageAlarm) - { - _voltageAlarm.RaiseAlarm(); - (_voltageAlarm as NewVoltageAlarm).ResetNumberOfAlarmsRaised(); // This is custom for the specific implementation. - } - else - { - _voltageAlarm.RaiseAlarm(); - }*/ - } - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_MFeathersExample/Program.cs b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_MFeathersExample/Program.cs index 5a73441..b09bdc9 100644 --- a/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_MFeathersExample/Program.cs +++ b/SOLIDprinciples/LiskovSubstitution/LiskovSubstitution_MFeathersExample/Program.cs @@ -1,13 +1,8 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LiskovSubstitution_MFeathersExample +namespace LiskovSubstitution_MFeathersExample { /// - /// An example of Liskov Substitution Violation from Michael Feathers, from his book "Working Effectively with Legacy Code", pg. 101-102. + /// An example of Liskov Substitution Violation from Michael Feathers, from his + /// book "Working Effectively with Legacy Code", pg. 101-102. /// public class Program { @@ -15,15 +10,16 @@ static void Main(string[] args) { // Square inherits the SetWidth and SetHeight methods of Rectangle. Rectangle r = new Square(3); + // What should the area be when we execute this code...? r.SetHeight(3); r.SetWidth(4); - // So, not really a *square* after all...? Liskov Substition violation. + // So, not really a *square* after all...? Liskov Substitution violation. // We could just override SetWidth and SetHeight so that they keep the square 'square', but that could lead to some counter-intuitive results. // Anyone who expects that all rectangles will have an area of 12 when their width is set to 3 and their height set to 4 is in for a surprise - they would get 16 instead. - // This is a classic example of a LSP violation. Objects of subclasses should be substitutable for objects of their superclasses throughout our code. + // This is a classic example of a LSP violation. Objects of subclasses should be substitutable for objects of their super-classes throughout our code. // If they aren't we could have silent errors in our code. } } diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/HitPointModifiers/HitPointModifierBase.cs b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/HitPointModifiers/HitPointModifierBase.cs new file mode 100644 index 0000000..8e74f27 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/HitPointModifiers/HitPointModifierBase.cs @@ -0,0 +1,21 @@ +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public abstract class HitPointModifierBase + { + protected readonly int _modifierValue; + protected readonly int _abilityBonus; + + public HitPointModifierBase(int modifierValue, int abilityBonus) + { + _modifierValue = modifierValue; + _abilityBonus = abilityBonus; + } + + public virtual int CalculateModifierValue(int hitPointValue) + { + int modifierValue = _modifierValue + _abilityBonus; + return modifierValue; + } + + } +} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/HitPointModifiers/IntimidationHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/HitPointModifiers/IntimidationHitPointModifier.cs new file mode 100644 index 0000000..01e1934 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/HitPointModifiers/IntimidationHitPointModifier.cs @@ -0,0 +1,17 @@ +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public sealed class IntimidationHitPointModifier : HitPointModifierBase + { + private const int INTIMIDATION_FORCE = 3; + + public IntimidationHitPointModifier(int modifierValue, int abilityBonus): + base(modifierValue, abilityBonus) + { + } + + public int GetIntimidationForce() + { + return INTIMIDATION_FORCE; + } + } +} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/HitPointModifiers/ProficiencyHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/HitPointModifiers/ProficiencyHitPointModifier.cs new file mode 100644 index 0000000..3d6edee --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/HitPointModifiers/ProficiencyHitPointModifier.cs @@ -0,0 +1,25 @@ +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public sealed class ProficiencyHitPointModifier : HitPointModifierBase + { + private readonly ProficiencyLevel _proficiencyLevel; + + public ProficiencyHitPointModifier(int modifierValue, int abilityBonus, ProficiencyLevel proficiencyLevel) : + base(modifierValue, abilityBonus) + { + _proficiencyLevel = proficiencyLevel; + } + + public int EvaluateProficiencyLevel() + { + return (int)_proficiencyLevel; + } + } + + public enum ProficiencyLevel + { + Novice = 1, + Guardian = 5, + Legend = 15 + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/MagicSword.cs b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/MagicSword.cs new file mode 100644 index 0000000..6080a3d --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/MagicSword.cs @@ -0,0 +1,55 @@ +using OpenClosed_GoodDesign.HitPointModifiers; + +namespace OpenClosed_GoodDesign +{ + public sealed class MagicSword + { + private readonly HitPointModifierBase[] _hitPointModifiers; + + public MagicSword(HitPointModifierBase[] hitPointModifiers) + { + _hitPointModifiers = hitPointModifiers; + } + + /// + /// Gets the modifier values across all s. + /// + /// + /// This method breaks with the open/closed principle, in that we calculate the result in consideration + /// to a specific -type. So if we introduce a new type of , we must now + /// modify this method accordingly. + /// + public int GetTotalModifierValue(int hitPointValue) + { + int totalModifyValue = 0; + foreach (HitPointModifierBase hitPointModifier in _hitPointModifiers) + { + if (hitPointModifier is ProficiencyHitPointModifier) + { + int calculateModifierValue(int hitPointValue) + { + int modifierValue = hitPointModifier.CalculateModifierValue(hitPointValue); + int proficiencyLevel = ((ProficiencyHitPointModifier)hitPointModifier).EvaluateProficiencyLevel(); + int calculatedModifierValue = proficiencyLevel + modifierValue; + return calculatedModifierValue; + } + + totalModifyValue += calculateModifierValue(hitPointValue); + } + else if (hitPointModifier is IntimidationHitPointModifier) + { + int calculateModifierValue(int hitPointValue) + { + int modifierValue = hitPointModifier.CalculateModifierValue(hitPointValue); + int intimidationForce = ((IntimidationHitPointModifier)hitPointModifier).GetIntimidationForce(); + int calculatedModifierValue = intimidationForce + modifierValue; + return calculatedModifierValue; + } + totalModifyValue += calculateModifierValue(hitPointValue); + } + } + + return totalModifyValue; + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorImplementations/ExternalTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorImplementations/ExternalTankPressureSensor.cs deleted file mode 100644 index ea687a7..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorImplementations/ExternalTankPressureSensor.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace OpenClosed_BadDesign.PressureSensorImplementations -{ - public sealed class ExternalTankPressureSensor : TankPressureSensorBase - { - private const int TANK_ISOLATION_IMPEDANCE = 3; - private const int TANK_ISOLATION_THICKNESS = 42; - - public ExternalTankPressureSensor(int tankCapacity = 3, int tankDiameter = 10): - base(tankCapacity, tankDiameter) - { - } - - public double GetTankIsolationFactor() - { - return (double)TANK_ISOLATION_THICKNESS / TANK_ISOLATION_IMPEDANCE; - } - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorImplementations/InternalTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorImplementations/InternalTankPressureSensor.cs deleted file mode 100644 index e37ecea..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorImplementations/InternalTankPressureSensor.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace OpenClosed_BadDesign.PressureSensorImplementations -{ - public sealed class InternalTankPressureSensor : TankPressureSensorBase - { - public const int TANK_INTERNAL_THICKNESS = 15; - - public InternalTankPressureSensor(int tankCapacity = 3, int tankDiameter = 10) : - base(tankCapacity, tankDiameter) - { - } - - public override double CalculateTankOutletSize() - { - double tankOutletSize = ((double) _tankCapacity / _tankDiameter) * 2; - return tankOutletSize; - } - - - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorImplementations/TankPressureSensorBase.cs b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorImplementations/TankPressureSensorBase.cs deleted file mode 100644 index 3acb11b..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorImplementations/TankPressureSensorBase.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace OpenClosed_BadDesign.PressureSensorImplementations -{ - public abstract class TankPressureSensorBase - { - protected readonly int _tankCapacity = 10; - protected readonly int _tankDiameter = 3; - - public TankPressureSensorBase(int tankCapacity = 3, int tankDiameter = 10) - { - _tankCapacity = tankCapacity; - _tankDiameter = tankDiameter; - } - - public virtual double CalculateTankOutletSize() - { - double tankOutletSize = (double)_tankCapacity / _tankDiameter; - return tankOutletSize; - } - - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorReader.cs b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorReader.cs deleted file mode 100644 index 96c9451..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/PressureSensorReader.cs +++ /dev/null @@ -1,57 +0,0 @@ -using OpenClosed_BadDesign.PressureSensorImplementations; -using System.Diagnostics; -using System.Runtime.CompilerServices; - -namespace OpenClosed_BadDesign -{ - public sealed class PressureSensorReader - { - private readonly TankPressureSensorBase[] _tankPressureSensors; - - public PressureSensorReader(TankPressureSensorBase[] tankPressureSensors) - { - _tankPressureSensors = tankPressureSensors; - } - - /// - /// Gets the average pressure across all sensors. - /// - /// - /// This method breaks with the open/closed principle, in that we calculate the result in consideration - /// to a specific sensor-type. So if we introduce a new type of sensor, we must now modify this method accordingly. - /// - public double GetAveragePressureAcrossSensors(int waterIntakeVelocity) - { - double totalPressureFromAllSensors = 0; - - foreach (TankPressureSensorBase tankPressureSensor in _tankPressureSensors) - { - if (tankPressureSensor is InternalTankPressureSensor) - { - double calculatePressure(int waterIntakeVelocity) - { - double internalTankOutletSize = tankPressureSensor.CalculateTankOutletSize(); - double totallyBogusPressureValue = (InternalTankPressureSensor.TANK_INTERNAL_THICKNESS * waterIntakeVelocity) * internalTankOutletSize; - return totallyBogusPressureValue; - } - totalPressureFromAllSensors += calculatePressure(waterIntakeVelocity); - } - else if (tankPressureSensor is ExternalTankPressureSensor) - { - double calculatePressure(int waterIntakeVelocity) - { - double tankOutletSize = tankPressureSensor.CalculateTankOutletSize(); - double tankIsolationFactor = ((ExternalTankPressureSensor)tankPressureSensor).GetTankIsolationFactor(); - double totallyBogusPressureValue = tankIsolationFactor * tankOutletSize; - return totallyBogusPressureValue; - } - totalPressureFromAllSensors += calculatePressure(waterIntakeVelocity); - } - } - - int numberOfPressureSensors = _tankPressureSensors.Length; - double averagePressureAcrossSensors = totalPressureFromAllSensors / numberOfPressureSensors; - return averagePressureAcrossSensors; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/Program.cs b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/Program.cs index 8fa3695..2a8a81c 100644 --- a/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/Program.cs +++ b/SOLIDprinciples/OpenClosed/OpenClosed_BadDesign/Program.cs @@ -1,7 +1,7 @@ -using OpenClosed_BadDesign.PressureSensorImplementations; +using OpenClosed_GoodDesign.HitPointModifiers; using System.Diagnostics; -namespace OpenClosed_BadDesign +namespace OpenClosed_GoodDesign { /// /// The Open/Closed Principle states that a component should be closed for modification, but open for extensions. In the below, @@ -9,22 +9,18 @@ namespace OpenClosed_BadDesign /// public sealed class Program { - /// - /// - /// public static void Main() { - TankPressureSensorBase[] tankPressureSensors = + HitPointModifierBase[] hitPointModifiers = { - new InternalTankPressureSensor(tankCapacity: 4), - new InternalTankPressureSensor(tankDiameter: 15), - new ExternalTankPressureSensor(1, 100) + new ProficiencyHitPointModifier(modifierValue: 4, abilityBonus: 1, ProficiencyLevel.Guardian), + new IntimidationHitPointModifier( modifierValue: 10, abilityBonus: 1) }; - PressureSensorReader pressureSensorReader = new(tankPressureSensors); + MagicSword magicSword = new(hitPointModifiers); - int waterIntakeVelocity = 16; - double averagePressureAcrossSensors = pressureSensorReader.GetAveragePressureAcrossSensors(waterIntakeVelocity); - Debug.WriteLine($"Average pressure across all pressure sensors is {averagePressureAcrossSensors}"); + int hitPoints = 16; + int totalModifierValue = magicSword.GetTotalModifierValue(hitPoints); + Debug.WriteLine($"{nameof(totalModifierValue)} across all {nameof(hitPointModifiers)} is {totalModifierValue}"); } } } \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Decorators/ShockAbsorbableTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Decorators/ShockAbsorbableTankPressureSensor.cs deleted file mode 100644 index 159507f..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Decorators/ShockAbsorbableTankPressureSensor.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Diagnostics; - -namespace OpenClosed_DecoratorPattern.PressureSensorImplementations -{ - public sealed class ShockAbsorbableTankPressureSensor : TankPressureSensorDecorator - { - private const double PRESSURE_INCREASE_FACTOR_IF_SHOCKABSORBABLE = 1.1; - - private readonly double _maXAllowableGForceLoad = 5d; - - public ShockAbsorbableTankPressureSensor(double? maXAllowableGForceLoad, TankPressureSensorBase abstractTankPressureSensor) : - base(abstractTankPressureSensor) - { - _maXAllowableGForceLoad = maXAllowableGForceLoad.Value; - } - - public override double CalculatePressure(int waterIntakeVelocity) - { - Debug.WriteLine($"Called CalculatePressure() on {this.GetType().Name}"); - - bool isShockAbsorbent = Is5GShockAbsorbent(); - if (isShockAbsorbent) - return base.CalculatePressure(waterIntakeVelocity) * PRESSURE_INCREASE_FACTOR_IF_SHOCKABSORBABLE; - else - return base.CalculatePressure(waterIntakeVelocity); - } - - private bool Is5GShockAbsorbent() - { - bool isShockAbsorbentUpTo5G = _maXAllowableGForceLoad < 5d; - return isShockAbsorbentUpTo5G; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Decorators/TankPressureSensorDecorator.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Decorators/TankPressureSensorDecorator.cs deleted file mode 100644 index a455f51..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Decorators/TankPressureSensorDecorator.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace OpenClosed_DecoratorPattern.PressureSensorImplementations -{ - /// - /// This holds a implementation - /// as a private field. By implementing this abstract class, we can keep adding relevant logic in regards to - /// the ; each referenced implementation will reference - or - /// 'decorate' - the implementation it's based on - as best seen in the method. - /// - public abstract class TankPressureSensorDecorator : TankPressureSensorBase - { - private readonly TankPressureSensorBase _abstractTankPressureSensor; - - public TankPressureSensorDecorator(TankPressureSensorBase abstractTankPressureSensor) - { - _abstractTankPressureSensor = abstractTankPressureSensor; - } - - public override double CalculatePressure(int waterIntakeVelocity) - { - return _abstractTankPressureSensor.CalculatePressure(waterIntakeVelocity); - } - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Decorators/TemperatureTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Decorators/TemperatureTankPressureSensor.cs deleted file mode 100644 index fbec249..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Decorators/TemperatureTankPressureSensor.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Diagnostics; - -namespace OpenClosed_DecoratorPattern.PressureSensorImplementations -{ - /// - /// A -implementation, which differs the pressure calculation if the sensor's operating temperature are - /// within a minimum and a maximum value. - /// - public sealed class TemperatureTankPressureSensor : TankPressureSensorDecorator - { - private const double PRESSURE_INCREASE_FACTOR_IF_WITHIN_TEMPERATURE_OPERATING_WINDOW = 1.5; - - private readonly int _minimumDegreesCelsius; - private readonly int _maxDegreesCelsius; - - public TemperatureTankPressureSensor(int minimumDegreesCelsius, int maxDegreesCelsius, TankPressureSensorBase abstractTankPressureSensor) : - base(abstractTankPressureSensor) - { - _minimumDegreesCelsius = minimumDegreesCelsius; - _maxDegreesCelsius = maxDegreesCelsius; - } - - public override double CalculatePressure(int waterIntakeVelocity) - { - Debug.WriteLine($"Called CalculatePressure() on {this.GetType().Name}"); - - int currentOperatingTemperature = getCurrentOperatingTemperature(); - bool isOperatingTemperatureWithinWindow = IsOperatingTemperatureWithinWindow(currentOperatingTemperature); - - if (isOperatingTemperatureWithinWindow) - return base.CalculatePressure(waterIntakeVelocity) * PRESSURE_INCREASE_FACTOR_IF_WITHIN_TEMPERATURE_OPERATING_WINDOW; - else - return base.CalculatePressure(waterIntakeVelocity); - } - - private bool IsOperatingTemperatureWithinWindow(int operatingTemperature) - { - if (_maxDegreesCelsius >= operatingTemperature && operatingTemperature >= _minimumDegreesCelsius) - return true; - else - return false; - } - - private int getCurrentOperatingTemperature() - { - // simulate a reading of a temperature sensor - Random rnd = new(); - int currentOperatingTemperature = rnd.Next(10, 30); - return currentOperatingTemperature; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/HitPointModifierBase.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/HitPointModifierBase.cs new file mode 100644 index 0000000..6883b2b --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/HitPointModifierBase.cs @@ -0,0 +1,25 @@ +using System.Diagnostics; + +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + + public abstract class HitPointModifierBase : IHitPointModifier + { + protected readonly int _modifierValue; + protected readonly int _abilityBonus; + + public HitPointModifierBase(int modifierValue, int abilityBonus) + { + _modifierValue = modifierValue; + _abilityBonus = abilityBonus; + } + + public virtual int CalculateModifierValue(int hitPointValue) + { + int modifierValue = _modifierValue + _abilityBonus; + Debug.WriteLine($"{this.GetType().Name} returns {modifierValue}"); + return modifierValue; + } + + } +} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/HitPointModifierDecorator.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/HitPointModifierDecorator.cs new file mode 100644 index 0000000..d10dda0 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/HitPointModifierDecorator.cs @@ -0,0 +1,32 @@ +using System; + +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + /// + /// The class 'wraps' the implementation and maintains a + /// reference - - to an . When classes such as + /// implements this decorator-class, they send an interface implementations along - which allows us to chain, or decorate, similar implementations and + /// inject new functionality into existing sub-classes. + /// + public abstract class HitPointModifierDecorator : HitPointModifierBase + { + private readonly IHitPointModifier _hitPointModifier; + + protected HitPointModifierDecorator(int modifierValue, int abilityBonus, IHitPointModifier hitPointModifier) : + base(modifierValue, abilityBonus) + { + _hitPointModifier = hitPointModifier; + } + + /// + /// Implements the method with an option to override. + /// + public override int CalculateModifierValue(int hitPointValue) + { + int decoratorHitPointModifier = _hitPointModifier.CalculateModifierValue(hitPointValue); + int baseHitPointModifier = base.CalculateModifierValue(hitPointValue); + + return baseHitPointModifier + decoratorHitPointModifier; + } + } +} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/IHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/IHitPointModifier.cs new file mode 100644 index 0000000..ab47e4e --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/IHitPointModifier.cs @@ -0,0 +1,7 @@ +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public interface IHitPointModifier + { + int CalculateModifierValue(int hitPointValue); + } +} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/IntimidationHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/IntimidationHitPointModifier.cs new file mode 100644 index 0000000..8dae50a --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/IntimidationHitPointModifier.cs @@ -0,0 +1,23 @@ +using System.Diagnostics; + +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public sealed class IntimidationHitPointModifier : HitPointModifierDecorator + { + private const int INTIMIDATION_FORCE = 3; + + public IntimidationHitPointModifier(int modifierValue, int abilityBonus, IHitPointModifier hitPointModifier) : + base(modifierValue, abilityBonus, hitPointModifier) + { + } + + public override int CalculateModifierValue(int hitPointValue) + { + int modifierValue = base.CalculateModifierValue(hitPointValue); + Debug.WriteLine($"Returning {modifierValue} from a {base.GetType().Name}. Will be added."); + int calculatedModifierValue = INTIMIDATION_FORCE + modifierValue; + Debug.WriteLine($"When adding the {nameof(INTIMIDATION_FORCE)} of {INTIMIDATION_FORCE} we return {calculatedModifierValue}."); + return calculatedModifierValue; + } + } +} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/NullObjectHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/NullObjectHitPointModifier.cs new file mode 100644 index 0000000..d4c3366 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/NullObjectHitPointModifier.cs @@ -0,0 +1,26 @@ +using System.Diagnostics; + +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + /// + /// A is an implementation of an that returns 0 (zero) for + /// its method. + /// + public sealed class NullObjectHitPointModifier : IHitPointModifier + { + public NullObjectHitPointModifier() + { + } + + public int CalculateModifierValue(int hitPointValue) + { + Debug.WriteLine($"{typeof(NullObjectHitPointModifier).Name} returns 0"); + return 0; + } + + public static NullObjectHitPointModifier Create() + { + return new NullObjectHitPointModifier(); + } + } +} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/ProficiencyHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/ProficiencyHitPointModifier.cs new file mode 100644 index 0000000..78f3720 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/HitPointModifiers/ProficiencyHitPointModifier.cs @@ -0,0 +1,37 @@ +using System.Diagnostics; + +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public sealed class ProficiencyHitPointModifier : HitPointModifierDecorator + { + private readonly ProficiencyLevel _proficiencyLevel; + + public ProficiencyHitPointModifier(int modifierValue, int abilityBonus, ProficiencyLevel proficiencyLevel, IHitPointModifier hitPointModifier) : + base(modifierValue, abilityBonus, hitPointModifier) + { + _proficiencyLevel = proficiencyLevel; + } + + public override int CalculateModifierValue(int hitPointValue) + { + int modifierValue = base.CalculateModifierValue(hitPointValue); + Debug.WriteLine($"Returning {modifierValue} from a {base.GetType().Name}. Will be added."); + int proficiencyLevel = EvaluateProficiencyLevel(); + int calculatedModifierValue = proficiencyLevel + modifierValue; + Debug.WriteLine($"When adding the {nameof(proficiencyLevel)} of {proficiencyLevel} we return {calculatedModifierValue}."); + return calculatedModifierValue; + } + + public int EvaluateProficiencyLevel() + { + return (int)_proficiencyLevel; + } + } + + public enum ProficiencyLevel + { + Novice = 1, + Guardian = 5, + Legend = 15 + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/MagicSword.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/MagicSword.cs new file mode 100644 index 0000000..85f2be9 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/MagicSword.cs @@ -0,0 +1,25 @@ +using OpenClosed_GoodDesign.HitPointModifiers; +using System.Linq; + +namespace OpenClosed_GoodDesign +{ + public sealed class MagicSword + { + private readonly HitPointModifierDecorator _hitPointModifierDecorator; + + public MagicSword(HitPointModifierDecorator hitPointModifierDecorator) + { + _hitPointModifierDecorator = hitPointModifierDecorator; + } + + /// + /// Gets the modifier values by un-winding all s. + /// + /// + public double GetTotalModifierValue(int hitPointValue) + { + double totalModifyValue = _hitPointModifierDecorator.CalculateModifierValue(hitPointValue); + return totalModifyValue; + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorImplementations/ExternalTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorImplementations/ExternalTankPressureSensor.cs deleted file mode 100644 index 425e8d2..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorImplementations/ExternalTankPressureSensor.cs +++ /dev/null @@ -1,31 +0,0 @@ - -using System.Diagnostics; - -namespace OpenClosed_DecoratorPattern.PressureSensorImplementations -{ - public sealed class ExternalTankPressureSensor : TankPressureSensorBase - { - private const int TANK_ISOLATION_IMPEDANCE = 3; - private const int TANK_ISOLATION_THICKNESS = 42; - - public ExternalTankPressureSensor(int tankCapacity = 3, int tankDiameter = 10) : base(tankCapacity, tankDiameter) - { - } - - private double getTankIsolationFactor() - { - return (double)TANK_ISOLATION_THICKNESS / TANK_ISOLATION_IMPEDANCE; - } - - // Note - GetTankPressure() had its name changed to CalculatePressure(), to honor the base-class. - public override double CalculatePressure(int waterIntakeVelocity) - { - Debug.WriteLine($"Called CalculatePressure() on {this.GetType().Name}"); - - double tankOutletSize = CalculateTankOutletSize(); - double tankIsolationFactor = getTankIsolationFactor(); - double totallyBogusPressureValue = tankIsolationFactor * tankOutletSize; - return totallyBogusPressureValue; - } - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorImplementations/InternalTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorImplementations/InternalTankPressureSensor.cs deleted file mode 100644 index a35a12d..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorImplementations/InternalTankPressureSensor.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Diagnostics; - -namespace OpenClosed_DecoratorPattern.PressureSensorImplementations -{ - public sealed class InternalTankPressureSensor : TankPressureSensorBase - { - private const int TANK_INTERNAL_THICKNESS = 15; - - public InternalTankPressureSensor(int tankCapacity = 3, int tankDiameter = 10) : base(tankCapacity, tankDiameter) - { - } - - public override double CalculatePressure(int waterIntakeVelocity) - { - Debug.WriteLine($"Called CalculatePressure() on {this.GetType().Name}"); - - double internalTankoutletSize = CalculateTankOutletSize(); - double totallyBogusPressureValue = (TANK_INTERNAL_THICKNESS * waterIntakeVelocity) * internalTankoutletSize; - return totallyBogusPressureValue; - } - - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorImplementations/TankPressureSensorBase.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorImplementations/TankPressureSensorBase.cs deleted file mode 100644 index 7419083..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorImplementations/TankPressureSensorBase.cs +++ /dev/null @@ -1,28 +0,0 @@ - -using System; - -namespace OpenClosed_DecoratorPattern.PressureSensorImplementations -{ - - public abstract class TankPressureSensorBase - { - - private readonly int _tankCapacity = 10; - private readonly int _tankDiameter = 3; - - public TankPressureSensorBase(int tankCapacity = 3, int tankDiameter = 10) - { - - _tankCapacity = tankCapacity; - _tankDiameter = tankDiameter; - } - - protected double CalculateTankOutletSize() - { - double tankOutletSize = (double)_tankCapacity / _tankDiameter; - return tankOutletSize; - } - - public abstract double CalculatePressure(int waterIntakeVelocity); - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorReader.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorReader.cs deleted file mode 100644 index 0447b4d..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/PressureSensorReader.cs +++ /dev/null @@ -1,30 +0,0 @@ -using OpenClosed_DecoratorPattern.PressureSensorImplementations; -using System.Linq; - -namespace OpenClosed_DecoratorPattern -{ - public sealed class PressureSensorReader - { - private readonly TankPressureSensorBase[] _tankPressureSensors; - - public PressureSensorReader(TankPressureSensorBase[] tankPressureSensors) - { - _tankPressureSensors = tankPressureSensors; - - } - - public double GetAveragePressureAcrossSensors(int waterIntakeVelocity) - { - double totalPressureFromAllSensors = 0; - _tankPressureSensors.ToList().ForEach(sensor => - { - totalPressureFromAllSensors += sensor.CalculatePressure(waterIntakeVelocity); - }); - - int numberOfPressureSensors = _tankPressureSensors.Length; - double averagePressureAcrossSensors = totalPressureFromAllSensors / numberOfPressureSensors; - - return averagePressureAcrossSensors; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Program.cs b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Program.cs index 7c1c643..0dbb0ba 100644 --- a/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Program.cs +++ b/SOLIDprinciples/OpenClosed/OpenClosed_DecoratorPattern/Program.cs @@ -1,34 +1,25 @@ -using OpenClosed_DecoratorPattern.PressureSensorImplementations; +using OpenClosed_GoodDesign.HitPointModifiers; using System.Diagnostics; -namespace OpenClosed_DecoratorPattern +namespace OpenClosed_GoodDesign { - public static class Program + public sealed class Program { - /// - /// Now we're in the need to implement a tank-pressure sensor that takes into account temperatures, shock-absorbability, etc. - /// We can't keep on sub-classing AbstractTankPressureSensor's - we'd drown in implementations. Instead, we can use the - /// decorator pattern to add behavior, rather than continuously sub-classing. - /// - /// - /// The advantage of the decorator pattern is in how we can truly abstract away only that code which changes, in this case - /// the individual pressure-calculating logic. - /// public static void Main() { - TankPressureSensorBase internalTankPressureSensor = new InternalTankPressureSensor(tankCapacity: 4); + int hitPoints = 10; - TankPressureSensorBase shockAbsorbableInternalTankPressureSensor = - new ShockAbsorbableTankPressureSensor( maXAllowableGForceLoad: 10, internalTankPressureSensor); + HitPointModifierDecorator modifier1 = new IntimidationHitPointModifier(modifierValue: 6, abilityBonus: 1, NullObjectHitPointModifier.Create()); + //Debug.Assert(modifier1.CalculateModifierValue(hitPoints) == 10); // 6+1 +3 intimidation-points + 0 for the null-object modifier + HitPointModifierDecorator modifier2 = new ProficiencyHitPointModifier(modifierValue: 4, abilityBonus: 1, ProficiencyLevel.Guardian, modifier1); + //Debug.Assert(modifier2.CalculateModifierValue(hitPoints) == 20); // 4+1+(int)Guardian + 10 for modifier1 + HitPointModifierDecorator modifier3 = new IntimidationHitPointModifier(modifierValue: 3, abilityBonus: 2, modifier2); + //Debug.Assert(modifier3.CalculateModifierValue(hitPoints) == 28); // 3+2 +3 intimidation-points + 20 for modifier2 - TankPressureSensorBase shockAbsorbableInternalTankPressureSensorWithTemperature = - new TemperatureTankPressureSensor(minimumDegreesCelsius: 10, maxDegreesCelsius: 12, shockAbsorbableInternalTankPressureSensor); + MagicSword magicSword = new(modifier3); - TankPressureSensorBase[] tankPressureSensors = { shockAbsorbableInternalTankPressureSensorWithTemperature /* Just one sensor, for the case of this example. */ }; - - PressureSensorReader pressureSensorReader = new(tankPressureSensors); - double averagePressureAcrossSensors = pressureSensorReader.GetAveragePressureAcrossSensors(10); - Debug.WriteLine($"Average pressure across all pressure sensors is {averagePressureAcrossSensors}"); + double totalModifierValue = magicSword.GetTotalModifierValue(hitPoints); + Debug.WriteLine($"{nameof(totalModifierValue)} across all modifiers is {totalModifierValue}"); } } } \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/HitPointModifierBase.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/HitPointModifierBase.cs new file mode 100644 index 0000000..9c86aa3 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/HitPointModifierBase.cs @@ -0,0 +1,21 @@ +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public abstract class HitPointModifierBase : IHitPointModifier + { + protected readonly int _modifierValue; + protected readonly int _abilityBonus; + + public HitPointModifierBase(int modifierValue, int abilityBonus) + { + _modifierValue = modifierValue; + _abilityBonus = abilityBonus; + } + + public virtual double CalculateModifierValue(int hitPointValue) + { + int modifierValue = _modifierValue + _abilityBonus; + return modifierValue; + } + + } +} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/IHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/IHitPointModifier.cs new file mode 100644 index 0000000..dd26de3 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/IHitPointModifier.cs @@ -0,0 +1,7 @@ +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public interface IHitPointModifier + { + double CalculateModifierValue(int hitPointValue); + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/IntimidationHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/IntimidationHitPointModifier.cs new file mode 100644 index 0000000..f33a083 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/IntimidationHitPointModifier.cs @@ -0,0 +1,20 @@ +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public sealed class IntimidationHitPointModifier : HitPointModifierBase + { + private const double INTIMIDATION_FORCE = 3; + + public IntimidationHitPointModifier(int modifierValue, int abilityBonus) : + base(modifierValue, abilityBonus) + { + } + + public override double CalculateModifierValue(int hitPointValue) + { + double modifierValue = base.CalculateModifierValue(hitPointValue); + double calculatedModifierValue = INTIMIDATION_FORCE + modifierValue; + return calculatedModifierValue; + } + } +} + diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/ProficiencyHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/ProficiencyHitPointModifier.cs new file mode 100644 index 0000000..55355e3 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/HitPointModifiers/ProficiencyHitPointModifier.cs @@ -0,0 +1,33 @@ +namespace OpenClosed_GoodDesign.HitPointModifiers +{ + public sealed class ProficiencyHitPointModifier : HitPointModifierBase + { + private readonly ProficiencyLevel _proficiencyLevel; + + public ProficiencyHitPointModifier(int modifierValue, int abilityBonus, ProficiencyLevel proficiencyLevel) : + base(modifierValue, abilityBonus) + { + _proficiencyLevel = proficiencyLevel; + } + + public override double CalculateModifierValue(int hitPointValue) + { + double modifierValue = base.CalculateModifierValue(hitPointValue); + double calculatedModifierValue = modifierValue + EvaluateProficiencyLevel(); + return calculatedModifierValue; + } + + public int EvaluateProficiencyLevel() + { + return (int)_proficiencyLevel; + } + } + + public enum ProficiencyLevel + { + Novice = 1, + Guardian = 5, + Legend = 15 + } + +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/MagicSword.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/MagicSword.cs new file mode 100644 index 0000000..7c564b3 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/MagicSword.cs @@ -0,0 +1,25 @@ +using OpenClosed_GoodDesign.HitPointModifiers; +using System.Linq; + +namespace OpenClosed_GoodDesign +{ + public sealed class MagicSword + { + private readonly HitPointModifierBase[] _hitPointModifiers; + + public MagicSword(HitPointModifierBase[] hitPointModifiers) + { + _hitPointModifiers = hitPointModifiers; + } + + /// + /// Gets the modifier values across all s. + /// + /// + public double GetTotalModifierValue(int hitPointValue) + { + double totalModifyValue = _hitPointModifiers.Sum(hitPointModifier => hitPointModifier.CalculateModifierValue(hitPointValue)); + return totalModifyValue; + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorImplementations/ExternalTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorImplementations/ExternalTankPressureSensor.cs deleted file mode 100644 index ac45173..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorImplementations/ExternalTankPressureSensor.cs +++ /dev/null @@ -1,27 +0,0 @@ - -namespace OpenClosed_GoodDesign.PressureSensorImplementations -{ - public sealed class ExternalTankPressureSensor : TankPressureSensorBase - { - private const int TANK_ISOLATION_IMPEDANCE = 3; - private const int TANK_ISOLATION_THICKNESS = 42; - - public ExternalTankPressureSensor(int tankCapacity = 3, int tankDiameter = 10) : - base(tankCapacity, tankDiameter) - { - } - - private double getTankIsolationFactor() - { - return (double)TANK_ISOLATION_THICKNESS / TANK_ISOLATION_IMPEDANCE; - } - - public override double CalculatePressure(int waterIntakeVelocity) - { - double tankOutletSize = CalculateTankOutletSize(); - double tankIsolationFactor = getTankIsolationFactor(); - double totallyBogusPressureValue = tankIsolationFactor * tankOutletSize; - return totallyBogusPressureValue; - } - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorImplementations/InternalTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorImplementations/InternalTankPressureSensor.cs deleted file mode 100644 index 64dcdc2..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorImplementations/InternalTankPressureSensor.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace OpenClosed_GoodDesign.PressureSensorImplementations -{ - public sealed class InternalTankPressureSensor : TankPressureSensorBase - { - private const int TANK_INTERNAL_THICKNESS = 15; - - public InternalTankPressureSensor(int tankCapacity = 3, int tankDiameter = 10) : - base(tankCapacity, tankDiameter) - { - } - - public override double CalculateTankOutletSize() - { - double tankOutletSize = ((double)_tankCapacity / _tankDiameter) * 2; - return tankOutletSize; - } - - public override double CalculatePressure(int waterIntakeVelocity) - { - double internalTankOutletSize = CalculateTankOutletSize(); - double totallyBogusPressureValue = (TANK_INTERNAL_THICKNESS * waterIntakeVelocity) * internalTankOutletSize; - return totallyBogusPressureValue; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorImplementations/TankPressureSensorBase.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorImplementations/TankPressureSensorBase.cs deleted file mode 100644 index 7e88d75..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorImplementations/TankPressureSensorBase.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace OpenClosed_GoodDesign.PressureSensorImplementations -{ - /// - /// By moving the individual 'CalculatePressure' concerns into the base-class, we can forego - /// taking the distinct tankPressureSensor-implementations into account when the PressureSensorReader - /// calculates the combined pressures. - /// - public abstract class TankPressureSensorBase - { - protected readonly int _tankCapacity = 10; - protected readonly int _tankDiameter = 3; - - public TankPressureSensorBase(int tankCapacity = 3, int tankDiameter = 10) - { - _tankCapacity = tankCapacity; - _tankDiameter = tankDiameter; - } - - public virtual double CalculateTankOutletSize() - { - double tankOutletSize = (double)_tankCapacity / _tankDiameter; - return tankOutletSize; - } - - public abstract double CalculatePressure(int waterIntakeVelocity); - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorReader.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorReader.cs deleted file mode 100644 index b9d2585..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/PressureSensorReader.cs +++ /dev/null @@ -1,34 +0,0 @@ -using OpenClosed_GoodDesign.PressureSensorImplementations; -using System.Linq; - -namespace OpenClosed_GoodDesign -{ - public sealed class PressureSensorReader - { - private readonly TankPressureSensorBase[] _tankPressureSensors; - - public PressureSensorReader(TankPressureSensorBase[] tankPressureSensors) - { - _tankPressureSensors = tankPressureSensors; - } - - /// - /// Gets the average pressure across all sensors. - /// - /// - /// Given the introduction of the abstraction, we needn't modify the method if we introduce a new type of sensor. - /// - public double GetAveragePressureAcrossSensors(int waterIntakeVelocity) - { - double totalPressureFromAllSensors = 0; - _tankPressureSensors.ToList().ForEach(sensor => - { - totalPressureFromAllSensors += sensor.CalculatePressure(waterIntakeVelocity); - }); - - int numberOfPressureSensors = _tankPressureSensors.Length; - double averagePressureAcrossSensors = totalPressureFromAllSensors / numberOfPressureSensors; - return averagePressureAcrossSensors; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/Program.cs b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/Program.cs index 8dfaa60..ba9b4c0 100644 --- a/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/Program.cs +++ b/SOLIDprinciples/OpenClosed/OpenClosed_GoodDesign/Program.cs @@ -1,28 +1,22 @@ -using OpenClosed_GoodDesign.PressureSensorImplementations; +using OpenClosed_GoodDesign.HitPointModifiers; using System.Diagnostics; namespace OpenClosed_GoodDesign { public sealed class Program { - /// - /// In order to accommodate the open/closed principle, we move common concerns - i.e. the CalculatePressure-logic - into the - /// abstract class. This opens the class up to extensions by injection of multiple and - /// different sensors, and closes it for modification since the calculations are performed outside of the . - /// public static void Main() { - TankPressureSensorBase[] tankPressureSensors = - { - new InternalTankPressureSensor(tankCapacity: 4), - new InternalTankPressureSensor(tankDiameter: 15), - new ExternalTankPressureSensor(1, 100) + HitPointModifierBase[] hitPointModifiers = + { + new ProficiencyHitPointModifier(modifierValue: 4, abilityBonus: 1, ProficiencyLevel.Guardian), + new IntimidationHitPointModifier( modifierValue: 10, abilityBonus: 1) }; - PressureSensorReader pressureSensorReader = new(tankPressureSensors); + MagicSword magicSword = new(hitPointModifiers); - int waterIntakeVelocity = 16; - double averagePressureAcrossSensors = pressureSensorReader.GetAveragePressureAcrossSensors(waterIntakeVelocity); - Debug.WriteLine($"Average pressure across all pressure sensors is {averagePressureAcrossSensors}"); + int hitPoints = 16; + double totalModifierValue = magicSword.GetTotalModifierValue(hitPoints); + Debug.WriteLine($"{nameof(totalModifierValue)} across all {nameof(hitPointModifiers)} is {totalModifierValue}"); } } } \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/HitPointModifierBase.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/HitPointModifierBase.cs new file mode 100644 index 0000000..7af75ac --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/HitPointModifierBase.cs @@ -0,0 +1,21 @@ +namespace OpenClosed_StrategyPattern.HitPointModifiers +{ + public abstract class HitPointModifierBase : IHitPointModifier + { + protected readonly int _modifierValue; + protected readonly int _abilityBonus; + + public HitPointModifierBase(int modifierValue, int abilityBonus) + { + _modifierValue = modifierValue; + _abilityBonus = abilityBonus; + } + + public virtual double CalculateModifierValue(int hitPointValue) + { + int modifierValue = _modifierValue + _abilityBonus; + return modifierValue; + } + + } +} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/IHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/IHitPointModifier.cs new file mode 100644 index 0000000..330716f --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/IHitPointModifier.cs @@ -0,0 +1,7 @@ +namespace OpenClosed_StrategyPattern.HitPointModifiers +{ + public interface IHitPointModifier + { + double CalculateModifierValue(int hitPointValue); + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/IntimidationHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/IntimidationHitPointModifier.cs new file mode 100644 index 0000000..aebce18 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/IntimidationHitPointModifier.cs @@ -0,0 +1,23 @@ +using OpenClosed_StrategyPattern.IntimidationStrategies; + +namespace OpenClosed_StrategyPattern.HitPointModifiers +{ + public sealed class IntimidationHitPointModifier : HitPointModifierBase + { + private readonly IIntimidationForceStrategy _intimidationForceStrategy; + + public IntimidationHitPointModifier(int modifierValue, int abilityBonus, IIntimidationForceStrategy intimidationForceStrategy) : + base(modifierValue, abilityBonus) + { + _intimidationForceStrategy = intimidationForceStrategy; + } + + public override double CalculateModifierValue(int hitPointValue) + { + double modifierValue = base.CalculateModifierValue(hitPointValue); + double calculatedModifierValue = _intimidationForceStrategy.GetIntimidationForce() + modifierValue; + return calculatedModifierValue; + } + } +} + diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/ProficiencyHitPointModifier.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/ProficiencyHitPointModifier.cs new file mode 100644 index 0000000..3eb8f3f --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/HitPointModifiers/ProficiencyHitPointModifier.cs @@ -0,0 +1,33 @@ +namespace OpenClosed_StrategyPattern.HitPointModifiers +{ + public sealed class ProficiencyHitPointModifier : HitPointModifierBase + { + private readonly ProficiencyLevel _proficiencyLevel; + + public ProficiencyHitPointModifier(int modifierValue, int abilityBonus, ProficiencyLevel proficiencyLevel) : + base(modifierValue, abilityBonus) + { + _proficiencyLevel = proficiencyLevel; + } + + public override double CalculateModifierValue(int hitPointValue) + { + double modifierValue = base.CalculateModifierValue(hitPointValue); + double calculatedModifierValue = modifierValue + EvaluateProficiencyLevel(); + return calculatedModifierValue; + } + + public int EvaluateProficiencyLevel() + { + return (int)_proficiencyLevel; + } + } + + public enum ProficiencyLevel + { + Novice = 1, + Guardian = 5, + Legend = 15 + } + +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/IntimidationStrategies/IIntimidationForceStrategy.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/IntimidationStrategies/IIntimidationForceStrategy.cs new file mode 100644 index 0000000..857d0e9 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/IntimidationStrategies/IIntimidationForceStrategy.cs @@ -0,0 +1,8 @@ +namespace OpenClosed_StrategyPattern.IntimidationStrategies +{ + public interface IIntimidationForceStrategy + { + int GetIntimidationForce(); + } + +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/IntimidationStrategies/SpellAffectedIntimidationForceStrategy.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/IntimidationStrategies/SpellAffectedIntimidationForceStrategy.cs new file mode 100644 index 0000000..091d9d3 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/IntimidationStrategies/SpellAffectedIntimidationForceStrategy.cs @@ -0,0 +1,29 @@ +using System; + +namespace OpenClosed_StrategyPattern.IntimidationStrategies +{ + public sealed class SpellAffectedIntimidationForceStrategy : IIntimidationForceStrategy + { + private readonly Spell _spell; + + public SpellAffectedIntimidationForceStrategy(Spell spell) + { + _spell = spell; + } + + public int GetIntimidationForce() + { + int spellIntimidationForces = (int)_spell; + return spellIntimidationForces; + } + } + + [Flags] + public enum Spell + { + FireBreath = 1, + FrostWalk = 2, + EarthConsume = 4, + CloudMind = 8 + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/IntimidationStrategies/TauntIntimidationForceStrategy.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/IntimidationStrategies/TauntIntimidationForceStrategy.cs new file mode 100644 index 0000000..b91d6ef --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/IntimidationStrategies/TauntIntimidationForceStrategy.cs @@ -0,0 +1,30 @@ +using System; + +namespace OpenClosed_StrategyPattern.IntimidationStrategies +{ + public sealed class TauntIntimidationForceStrategy : IIntimidationForceStrategy + { + private readonly TauntLevel _tauntLevel; + + public TauntIntimidationForceStrategy(TauntLevel tauntLevel) + { + _tauntLevel = tauntLevel; + } + + public int GetIntimidationForce() + { + return _tauntLevel switch + { + TauntLevel.NoviceTaunt => 0, + TauntLevel.MasterTaunt => 3, + _ => throw new NotImplementedException($"{_tauntLevel} not implemented") + }; + } + } + + public enum TauntLevel + { + NoviceTaunt, + MasterTaunt + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/MagicSword.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/MagicSword.cs new file mode 100644 index 0000000..88666f3 --- /dev/null +++ b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/MagicSword.cs @@ -0,0 +1,25 @@ +using OpenClosed_StrategyPattern.HitPointModifiers; +using System.Linq; + +namespace OpenClosed_StrategyPattern +{ + public sealed class MagicSword + { + private readonly HitPointModifierBase[] _hitPointModifiers; + + public MagicSword(HitPointModifierBase[] hitPointModifiers) + { + _hitPointModifiers = hitPointModifiers; + } + + /// + /// Gets the modifier values across all s. + /// + /// + public double GetTotalModifierValue(int hitPointValue) + { + double totalModifyValue = _hitPointModifiers.Sum(hitPointModifier => hitPointModifier.CalculateModifierValue(hitPointValue)); + return totalModifyValue; + } + } +} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/ExternalTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/ExternalTankPressureSensor.cs deleted file mode 100644 index 8fb54aa..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/ExternalTankPressureSensor.cs +++ /dev/null @@ -1,30 +0,0 @@ - -using OpenClosed_StrategyPattern.PressureSensorImplementations.TankOutletSizeStrategies; - -namespace OpenClosed_StrategyPattern.PressureSensorImplementations -{ - public sealed class ExternalTankPressureSensor : TankPressureSensorBase - { - private const int TANK_ISOLATION_IMPEDANCE = 3; - private const int TANK_ISOLATION_THICKNESS = 42; - - public ExternalTankPressureSensor(int tankCapacity = 3, int tankDiameter = 10, ITankSizeStrategy tankOutletSizeCalculateStrategy = null) : - base(tankCapacity, tankDiameter, tankOutletSizeCalculateStrategy) - { - } - - private double getTankIsolationFactor() - { - return (double)TANK_ISOLATION_THICKNESS / TANK_ISOLATION_IMPEDANCE; - } - - // Note - GetTankPressure() had its name changed to CalculatePressure(), to honor the base-class. - public override double CalculatePressure(int waterIntakeVelocity) - { - double tankOutletSize = GetTankOutletSize(); - double tankIsolationFactor = getTankIsolationFactor(); - double totallyBogusPressureValue = tankIsolationFactor * tankOutletSize; - return totallyBogusPressureValue; - } - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/InternalTankPressureSensor.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/InternalTankPressureSensor.cs deleted file mode 100644 index a1bf91e..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/InternalTankPressureSensor.cs +++ /dev/null @@ -1,22 +0,0 @@ -using OpenClosed_StrategyPattern.PressureSensorImplementations.TankOutletSizeStrategies; -using System; - -namespace OpenClosed_StrategyPattern.PressureSensorImplementations -{ - public sealed class InternalTankPressureSensor : TankPressureSensorBase - { - private const int TANK_INTERNAL_THICKNESS = 15; - - public InternalTankPressureSensor(int tankCapacity = 3, int tankDiameter = 10, ITankSizeStrategy tankSizeStrategy = null) : - base(tankCapacity, tankDiameter, tankSizeStrategy) - { - } - - public override double CalculatePressure(int waterIntakeVelocity) - { - double internalTankOutletSize = GetTankOutletSize(); - double totallyBogusPressureValue = (TANK_INTERNAL_THICKNESS * waterIntakeVelocity) * internalTankOutletSize; - return totallyBogusPressureValue; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankOutletSizeStrategies/DefaultTankSizeStrategy.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankOutletSizeStrategies/DefaultTankSizeStrategy.cs deleted file mode 100644 index aec4afa..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankOutletSizeStrategies/DefaultTankSizeStrategy.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace OpenClosed_StrategyPattern.PressureSensorImplementations.TankOutletSizeStrategies -{ - public sealed class DefaultTankOutletSizeCalculateStrategy : ITankSizeStrategy - { - public double CalculateTankOutletSize(int tankCapacity, int tankDiameter) - { - double tankOutletSize = (double)tankCapacity / tankDiameter; - return tankOutletSize; - } - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankOutletSizeStrategies/ITankOutletSizeStrategy.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankOutletSizeStrategies/ITankOutletSizeStrategy.cs deleted file mode 100644 index 3070c5d..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankOutletSizeStrategies/ITankOutletSizeStrategy.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace OpenClosed_StrategyPattern.PressureSensorImplementations.TankOutletSizeStrategies -{ - public interface ITankSizeStrategy - { - double CalculateTankOutletSize(int tankCapacity, int tankDiameter); - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankOutletSizeStrategies/USTankSizeStrategy.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankOutletSizeStrategies/USTankSizeStrategy.cs deleted file mode 100644 index 7dd4e98..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankOutletSizeStrategies/USTankSizeStrategy.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace OpenClosed_StrategyPattern.PressureSensorImplementations.TankOutletSizeStrategies -{ - public sealed class UnitedStatesTankSizeStrategy : ITankSizeStrategy - { - private const double US_TANK_OUTLET_SIZE_MODIFIER = 1.1d; - - public double CalculateTankOutletSize(int tankCapacity, int tankDiameter) - { - double tankOutletSize = (double)tankCapacity / tankDiameter; - return tankOutletSize * US_TANK_OUTLET_SIZE_MODIFIER; - } - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankPressureSensorBase.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankPressureSensorBase.cs deleted file mode 100644 index af3968c..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorImplementations/TankPressureSensorBase.cs +++ /dev/null @@ -1,45 +0,0 @@ -using OpenClosed_StrategyPattern.PressureSensorImplementations.TankOutletSizeStrategies; - -namespace OpenClosed_StrategyPattern.PressureSensorImplementations -{ - public abstract class TankPressureSensorBase - { - protected readonly int _tankCapacity = 10; - protected readonly int _tankDiameter = 3; - - /// - /// A implementation, injected at object creation. - /// - private readonly ITankSizeStrategy _tankOutletSizeCalculateStrategy; - - public TankPressureSensorBase(int tankCapacity = 3, int tankDiameter = 10, ITankSizeStrategy tankOutletSizeCalculateStrategy = null) - { - _tankCapacity = tankCapacity; - _tankDiameter = tankDiameter; - - if (tankOutletSizeCalculateStrategy == null) - { - _tankOutletSizeCalculateStrategy = new DefaultTankOutletSizeCalculateStrategy(); // Guard clause - } - else - { - _tankOutletSizeCalculateStrategy = tankOutletSizeCalculateStrategy; - } - } - - public abstract double CalculatePressure(int waterIntakeVelocity); - - /// - /// Our method body appears the same, but its execution will wary according - /// to the implementation. That's a big advantages - - /// otherwise the different calculations would have to go into the classes and we've have to have - /// two * classes and two * , - /// each with their own () functions - /// - protected double GetTankOutletSize() - { - double tankOutletSize = _tankOutletSizeCalculateStrategy.CalculateTankOutletSize(_tankCapacity, _tankDiameter); - return tankOutletSize; - } - } -} diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorReader.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorReader.cs deleted file mode 100644 index b2581f3..0000000 --- a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/PressureSensorReader.cs +++ /dev/null @@ -1,33 +0,0 @@ -using OpenClosed_StrategyPattern.PressureSensorImplementations; -using OpenClosed_StrategyPattern.PressureSensorImplementations.TankOutletSizeStrategies; - -namespace OpenClosed_StrategyPattern -{ - /// - /// The remains the same as in the 'good' example; everything - /// in regards to the different concerns happens in the creation - /// of the implementations, i.e. we inject a suitable strategy - /// via their constructors. - /// - public sealed class PressureSensorReader - { - private readonly TankPressureSensorBase[] _tankPressureSensors; - - public PressureSensorReader(TankPressureSensorBase[] tankPressureSensors) - { - _tankPressureSensors = tankPressureSensors; - } - - public double GetAveragePressureAcrossSensors(int waterIntakeVelocity) - { - double totalPressureFromAllSensors = 0; - - foreach (TankPressureSensorBase tankPressureSensor in _tankPressureSensors) - totalPressureFromAllSensors += tankPressureSensor.CalculatePressure(waterIntakeVelocity); - - int numberOfPressureSensors = _tankPressureSensors.Length; - double averagePressureAcrossSensors = totalPressureFromAllSensors / numberOfPressureSensors; - return averagePressureAcrossSensors; - } - } -} \ No newline at end of file diff --git a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/Program.cs b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/Program.cs index 9d894d0..7c6cc52 100644 --- a/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/Program.cs +++ b/SOLIDprinciples/OpenClosed/OpenClosed_StrategyPattern/Program.cs @@ -1,35 +1,33 @@ -using OpenClosed_StrategyPattern.PressureSensorImplementations; -using OpenClosed_StrategyPattern.PressureSensorImplementations.TankOutletSizeStrategies; +using OpenClosed_StrategyPattern.HitPointModifiers; +using OpenClosed_StrategyPattern.IntimidationStrategies; using System.Diagnostics; namespace OpenClosed_StrategyPattern { /// - /// The plot thickens!: We now sell our pressure-sensor-reader to USA, and am now under obligation to calculate different - /// tank sizes (and thus the average pressures will be different), depending on where in the world our tanks are located. + /// The plot thickens!: We now need to provide different calculations for the . /// - /// We could do several new different tank-implementations, i.e. "InternalTankPressureSensorUS" and - /// "InternalTankPressureSensorRestOfTheWorld" - but it's only GetTankOutletSize() that changes, so seems like overkill. - /// No worries: we can infuse our with a , - /// so we don't have to make new near copies of classes, but maintain just one - that we thus keep open for extention. + /// We could do several new different variations of the class, i.e. "Taunt" or + /// "Rage" and similar, but it will only be the intimidation-force that changes, so + /// this seems like overkill. By using the strategy design pattern we don't have to make new near copies of classes, but can + /// maintain just one - that we thus keep open for extension. /// public sealed class Program { public static void Main() { - ITankSizeStrategy UnitedStatesTankSizeStrategy = new UnitedStatesTankSizeStrategy(); + HitPointModifierBase[] hitPointModifiers = + { + new ProficiencyHitPointModifier(modifierValue: 4, abilityBonus: 1, ProficiencyLevel.Guardian), + new IntimidationHitPointModifier( modifierValue: 10, abilityBonus: 1, new TauntIntimidationForceStrategy(TauntLevel.MasterTaunt) ), + new IntimidationHitPointModifier( modifierValue: 10, abilityBonus: 1, new SpellAffectedIntimidationForceStrategy(Spell.CloudMind ^ Spell.EarthConsume ) ) + }; + MagicSword magicSword = new(hitPointModifiers); - TankPressureSensorBase[] tankPressureSensors = - { - new InternalTankPressureSensor(tankCapacity: 4), - new InternalTankPressureSensor(tankDiameter: 15, tankSizeStrategy: UnitedStatesTankSizeStrategy), - new ExternalTankPressureSensor(tankCapacity: 1, tankDiameter: 100) - }; - PressureSensorReader pressureSensorReader = new(tankPressureSensors); - - int waterIntakeVelocity = 16; - double averagePressureAcrossSensors = pressureSensorReader.GetAveragePressureAcrossSensors(waterIntakeVelocity); - Debug.WriteLine($"Average pressure across all pressure sensors is {averagePressureAcrossSensors}"); + int hitPoints = 16; + double totalModifierValue = magicSword.GetTotalModifierValue(hitPoints); + Debug.WriteLine($"{nameof(totalModifierValue)} across all {nameof(hitPointModifiers)} is {totalModifierValue}"); } } + } \ No newline at end of file diff --git a/SOLIDprinciples/SingleResponsibility/SingleResponsibility_FacadePattern/FileLogger.cs b/SOLIDprinciples/SingleResponsibility/SingleResponsibility_FacadePattern/FileLogger.cs deleted file mode 100644 index c28aa1f..0000000 --- a/SOLIDprinciples/SingleResponsibility/SingleResponsibility_FacadePattern/FileLogger.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.IO; - -namespace SingleResponsibility_FaçadePattern -{ - public sealed class FileLogger - { - public void WriteToLog(string logMessage) - { - string tempFile = Path.GetTempFileName(); - File.WriteAllText(tempFile, logMessage); - } - } -} \ No newline at end of file diff --git a/SingleResponsibility_Shared/HitType.cs b/SingleResponsibility_Shared/HitType.cs index 4017aa0..a8edfe2 100644 --- a/SingleResponsibility_Shared/HitType.cs +++ b/SingleResponsibility_Shared/HitType.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace SingleResponsibility +namespace SingleResponsibility { public enum HitType { diff --git a/SingleResponsibility_Shared/LeaderboardService.cs b/SingleResponsibility_Shared/LeaderboardService.cs index f69e375..6dd3ed3 100644 --- a/SingleResponsibility_Shared/LeaderboardService.cs +++ b/SingleResponsibility_Shared/LeaderboardService.cs @@ -1,5 +1,4 @@ -using SingleResponsibility; -using System; +using System; using System.Collections.Generic; using System.Linq; diff --git a/SingleResponsibility_Shared/SaveGameService.cs b/SingleResponsibility_Shared/SaveGameService.cs index d0376d4..90d8b6c 100644 --- a/SingleResponsibility_Shared/SaveGameService.cs +++ b/SingleResponsibility_Shared/SaveGameService.cs @@ -1,5 +1,4 @@ -using SingleResponsibility; -using System.Collections.Generic; +using System.Collections.Generic; namespace SingleResponsibility { diff --git a/SolidPrinciples.Tests/LiskovSubstitutionTests.cs b/SolidPrinciples.Tests/LiskovSubstitutionTests.cs deleted file mode 100644 index b3ab9a8..0000000 --- a/SolidPrinciples.Tests/LiskovSubstitutionTests.cs +++ /dev/null @@ -1,127 +0,0 @@ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using LiskovSubstitution_BadDesign; - -namespace SolidPrinciples.Tests -{ - [TestClass] - public class LiskovSubstitutionTests - { - #region bad design tests - - [TestMethod] - public void BadDesign_StandardVoltageAlarmCanRaiseAlarm() - { - // arrange - double standardAlarmThresholdValue = -1d; - StandardVoltageAlarm standardVoltageAlarm = new(standardAlarmThresholdValue); - - // act - standardVoltageAlarm.RaiseAlarm(); - - // assert - Assert.AreEqual(standardVoltageAlarm.NumberOfAlarmsRaised, 1); - } - - [TestMethod] - public void BadDesign_StandardVoltageAlarmCanDetectVoltageDrop() - { - // arrange - double standardAlarmThresholdValue = 1d; - StandardVoltageAlarm standardVoltageAlarm = new(standardAlarmThresholdValue); - - // act - bool hasVoltageDroppedBelowThreshold = standardVoltageAlarm.HasVoltageDroppedBelowThreshold(0); - - // assert - Assert.IsTrue(hasVoltageDroppedBelowThreshold); - } - - [TestMethod] - public void BadDesign_NewVoltageAlarmCanRaiseAlarm_repeatsXtimes() - { - // arrange - double newVoltageAlarmThreshold = -1d; // make it so that no matter what, an alarm will be raised. - NewVoltageAlarm newVoltageAlarm = new(newVoltageAlarmThreshold); - - // act - newVoltageAlarm.RaiseAlarm(); // repeats alarm 3 times - - // assert - Assert.AreEqual(newVoltageAlarm.NumberOfAlarmsRaised, 3); - } - - [TestMethod] - public void BadDesign_NewVoltageAlarmCanResetAlarm() - { - // arrange - double newVoltageAlarmThreshold = -1d; // make it so that no matter what, an alarm will be raised. - NewVoltageAlarm newVoltageAlarm = new(newVoltageAlarmThreshold); - - // act - newVoltageAlarm.RaiseAlarm(); - newVoltageAlarm.ResetNumberOfAlarmsRaised(); - - // assert - Assert.AreEqual(newVoltageAlarm.NumberOfAlarmsRaised, 0); - } - - [TestMethod] - public void BadDesign_VolageSensorCanReadSensorValue() - { - // arrange - LiskovSubstitution_BadDesign.VoltageSensor voltageSensor = new(); - - // act - voltageSensor.ReadCurrentSensorVoltage(); - - // assert - Assert.IsTrue(voltageSensor.CurrentSensorVoltage > 3); - } - - #endregion - - #region good design tests - - [TestMethod] - public void GoodDesign_NewVoltageAlarmShouldResetAlarms() - { - // arrange - LiskovSubstitution_GoodDesign.VoltageAlarmBase newVoltageAlarm = new LiskovSubstitution_GoodDesign.NewVoltageAlarm(5d); - - // act - bool shouldResetNumberOfAlarmsRaised = newVoltageAlarm.ShouldResetNumberOfAlarmsRaised(); - - // assert - Assert.IsTrue(shouldResetNumberOfAlarmsRaised); - } - - [TestMethod] - public void GoodDesign_NewVoltageAlarmCanGetAlarmRepetitionsCount() - { - // arrange - LiskovSubstitution_GoodDesign.VoltageAlarmBase newVoltageAlarm = new LiskovSubstitution_GoodDesign.NewVoltageAlarm(5d); - - // act - int numberOfAlarmRepetitions = newVoltageAlarm.GetNumberOfAlarmRepetitions(); - - // assert - Assert.AreEqual(numberOfAlarmRepetitions, 3); - } - - [TestMethod] - public void GoodDesign_NewVoltageAlarmCanGetMaxVoltageLevelForAlarm() - { - // arrange - LiskovSubstitution_GoodDesign.VoltageAlarmBase newVoltageAlarm = new LiskovSubstitution_GoodDesign.NewVoltageAlarm(5d); - - // act - double maxAllowedVoltage = newVoltageAlarm.GetMaximumAllowableVoltageLevel(); - - // assert - Assert.AreEqual(maxAllowedVoltage, 5d); - } - - #endregion - } -} diff --git a/SolidPrinciples.Tests/OpenClosedTests.cs b/SolidPrinciples.Tests/OpenClosedTests.cs deleted file mode 100644 index f25ad82..0000000 --- a/SolidPrinciples.Tests/OpenClosedTests.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace SolidPrinciples.Tests -{ - [TestClass] - public class OpenClosedTests - { - #region bad design tests - - [TestMethod] - public void BadDesign_TestCanGetAveragePressureAcrossSensors() - { - // arrange - OpenClosed_BadDesign.PressureSensorReader pressureSensorReader = new(); - int waterIntakeVelocity = 1; - - // act - double averagePressureSensor = pressureSensorReader.GetAveragePressureAcrossSensors(waterIntakeVelocity); - - // assert - Assert.IsTrue(averagePressureSensor> 3d); - } - - [TestMethod] - public void BadDesign_TestCanGetInternalSensorPressure() - { - // arrange - OpenClosed_BadDesign.PressureSensorImplementations.InternalTankPressureSensor internalTankPressureSensor = new(); - int waterIntakeVelocity = 1; - - // act - double pressure = internalTankPressureSensor.CalculatePressure(waterIntakeVelocity); - - // assert - Assert.AreEqual(pressure, 4.5d); - } - - [TestMethod] - public void BadDesign_TestCanGetExternalSensorPressure() - { - // arrange - OpenClosed_BadDesign.PressureSensorImplementations.ExternalTankPressureSensor externalTankPressureSensor = new(); - int waterIntakeVelocity = 1; - - // act - double pressure = externalTankPressureSensor.GetTankPressure(waterIntakeVelocity); - - // assert - Assert.AreEqual(pressure, 4.2d); - } - - #endregion - - #region good design tests - - [TestMethod] - public void GoodDesign_TestCanGetAveragePressureAcrossSensors() - { - // arrange - OpenClosed_GoodDesign.PressureSensorReader pressureSensorReader = new(); - int waterIntakeVelocity = 1; - - // act - double averagePressureSensor = pressureSensorReader.GetAveragePressureAcrossSensors(waterIntakeVelocity); - - // assert - Assert.IsTrue(averagePressureSensor > 3d); - } - - [TestMethod] - public void GoodDesign_TestCanGetInternalSensorPressure() - { - // arrange - OpenClosed_GoodDesign.PressureSensorImplementations.TankPressureSensorBase internalTankPressureSensor = new OpenClosed_GoodDesign.PressureSensorImplementations.InternalTankPressureSensor(); - int waterIntakeVelocity = 1; - - // act - double pressure = internalTankPressureSensor.CalculatePressure(waterIntakeVelocity); - - // assert - Assert.AreEqual(pressure, 4.5d); - } - - [TestMethod] - public void GoodDesign_TestCanGetExternalSensorPressure() - { - // arrange - OpenClosed_GoodDesign.PressureSensorImplementations.TankPressureSensorBase externalTankPressureSensor = new OpenClosed_GoodDesign.PressureSensorImplementations.ExternalTankPressureSensor(); - int waterIntakeVelocity = 1; - - // act - double pressure = externalTankPressureSensor.CalculatePressure(waterIntakeVelocity); - - // assert - Assert.AreEqual(pressure, 4.2d); - } - - #endregion - - } -} diff --git a/SolidPrinciples.Tests/SingleResponsibilityTests.cs b/SolidPrinciples.Tests/SingleResponsibilityTests.cs deleted file mode 100644 index de842d9..0000000 --- a/SolidPrinciples.Tests/SingleResponsibilityTests.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.IO; -using System.Linq; - -namespace SolidPrinciples.Tests -{ - [TestClass] - public class SingleResponsibilityTests - { - #region bad design - tests - [TestMethod] - public void BadDesign_TestCanReadSensorvalue() - { - // arrange - SingleResponsibility_BadDesign.SensorReader sensorReader = new(); - - // act - string sensorValue = sensorReader.ReadSensorValue(); - - // assert - int sensorValueStringLength = sensorValue.Length; - Assert.AreEqual(sensorValueStringLength, 36); - } - - [TestMethod] - public void BadDesign_TestCanWriteToLogFile() - { - // arrange - SingleResponsibility_BadDesign.SensorReader sensorReader = new(); - string tempPathDir = Path.GetTempPath(); - - // act - int tempFilesPathCountBeforeWrite = Directory.EnumerateFiles(tempPathDir).Count(); - sensorReader.WriteSensorValueToLog("foobar"); - - // assert - int tempFilesPathCountAfterWrite = Directory.EnumerateFiles(tempPathDir).Count(); - Assert.AreEqual(tempFilesPathCountAfterWrite, tempFilesPathCountBeforeWrite + 1); - } - - #endregion - - #region good design - tests - - [TestMethod] - public void GoodDesign_TestCanReadSensorvalue() - { - // arrange - SingleResponsibility_GoodDesign.SensorReader sensorReader = new(); - - // act - string sensorValue = sensorReader.ReadSensorValue(); - - // assert - int sensorValueStringLength = sensorValue.Length; - Assert.AreEqual(sensorValueStringLength, 36); - } - - [TestMethod] - public void GoodDesign_TestCanWriteToLogFile() - { - // arrange - SingleResponsibility_GoodDesign.FileLogger fileLogger = new(); - string tempPathDir = Path.GetTempPath(); - - // act - int tempFilesPathCountBeforeWrite = Directory.EnumerateFiles(tempPathDir).Count(); - fileLogger.WriteToLog("foobar"); - - // assert - int tempFilesPathCountAfterWrite = Directory.EnumerateFiles(tempPathDir).Count(); - Assert.AreEqual(tempFilesPathCountAfterWrite, tempFilesPathCountBeforeWrite + 1); - } - - #endregion - - } -} diff --git a/SolidPrinciples.Tests/SolidPrinciples.Tests.csproj b/SolidPrinciples.Tests/SolidPrinciples.Tests.csproj deleted file mode 100644 index 7c4ecc3..0000000 --- a/SolidPrinciples.Tests/SolidPrinciples.Tests.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - net8.0 - false - SolidPrinciples.Tests - SolidPrinciples.Tests - None - 1.0.0.0 - 1.0.0.0 - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file