From b9e8eb590c6c0776ebdec50e1a42642fd58fe938 Mon Sep 17 00:00:00 2001 From: tikaiz Date: Tue, 20 Jan 2026 10:30:21 +0100 Subject: [PATCH] Add Design Patterns --- .gitignore | 3 +- DecoratorLib/Component.cs | 9 +++++ DecoratorLib/DecoratorLib.csproj | 9 +++++ DecoratorLib/IComponent.cs | 6 +++ DesignPatterns.sln | 18 +++++++++ DesignPatterns/Builder/Warehouse.cs | 27 +++++++++++++ .../Decorator/ComponentDecorator.cs | 9 +++++ .../FailableComponentComponentDecorator.cs | 22 ++++++++++ DesignPatterns/DesignPatterns.csproj | 6 +++ DesignPatterns/Factory/Book.cs | 11 +++++ DesignPatterns/Factory/Product.cs | 16 ++++++++ DesignPatterns/Factory/Smartphone.cs | 11 +++++ DesignPatterns/Program.cs | 40 ++++++++++++++++++- DesignPatterns/Singleton/LoggerSingleton.cs | 17 ++++++++ DesignPatterns/Visitor/LoggingVisitor.cs | 16 ++++++++ ProxyLib/ConcreteSubject.cs | 10 +++++ ProxyLib/ISubject.cs | 6 +++ ProxyLib/ProxyLib.csproj | 9 +++++ ProxyLib/SubjectProxy.cs | 13 ++++++ VisitorLib/Circle.cs | 10 +++++ VisitorLib/IShapeVisitor.cs | 7 ++++ VisitorLib/Rectangle.cs | 10 +++++ VisitorLib/Shape.cs | 6 +++ VisitorLib/VisitorLib.csproj | 10 +++++ 24 files changed, 298 insertions(+), 3 deletions(-) create mode 100644 DecoratorLib/Component.cs create mode 100644 DecoratorLib/DecoratorLib.csproj create mode 100644 DecoratorLib/IComponent.cs create mode 100644 DesignPatterns/Builder/Warehouse.cs create mode 100644 DesignPatterns/Decorator/ComponentDecorator.cs create mode 100644 DesignPatterns/Decorator/FailableComponentComponentDecorator.cs create mode 100644 DesignPatterns/Factory/Book.cs create mode 100644 DesignPatterns/Factory/Product.cs create mode 100644 DesignPatterns/Factory/Smartphone.cs create mode 100644 DesignPatterns/Singleton/LoggerSingleton.cs create mode 100644 DesignPatterns/Visitor/LoggingVisitor.cs create mode 100644 ProxyLib/ConcreteSubject.cs create mode 100644 ProxyLib/ISubject.cs create mode 100644 ProxyLib/ProxyLib.csproj create mode 100644 ProxyLib/SubjectProxy.cs create mode 100644 VisitorLib/Circle.cs create mode 100644 VisitorLib/IShapeVisitor.cs create mode 100644 VisitorLib/Rectangle.cs create mode 100644 VisitorLib/Shape.cs create mode 100644 VisitorLib/VisitorLib.csproj diff --git a/.gitignore b/.gitignore index f400df3..76c5b41 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ obj/ /packages/ riderModule.iml /_ReSharper.Caches/ -.idea/ \ No newline at end of file +.idea/ +*.user \ No newline at end of file diff --git a/DecoratorLib/Component.cs b/DecoratorLib/Component.cs new file mode 100644 index 0000000..8fcc3ef --- /dev/null +++ b/DecoratorLib/Component.cs @@ -0,0 +1,9 @@ +namespace DecoratorLib; + +public class Component : IComponent +{ + public void Log() + { + Console.WriteLine("Component Log"); + } +} diff --git a/DecoratorLib/DecoratorLib.csproj b/DecoratorLib/DecoratorLib.csproj new file mode 100644 index 0000000..237d661 --- /dev/null +++ b/DecoratorLib/DecoratorLib.csproj @@ -0,0 +1,9 @@ + + + + net10.0 + enable + enable + + + diff --git a/DecoratorLib/IComponent.cs b/DecoratorLib/IComponent.cs new file mode 100644 index 0000000..037615c --- /dev/null +++ b/DecoratorLib/IComponent.cs @@ -0,0 +1,6 @@ +namespace DecoratorLib; + +public interface IComponent +{ + void Log(); +} diff --git a/DesignPatterns.sln b/DesignPatterns.sln index f164996..1190bc3 100644 --- a/DesignPatterns.sln +++ b/DesignPatterns.sln @@ -2,6 +2,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DesignPatterns", "DesignPatterns\DesignPatterns.csproj", "{97DCCECE-E259-4D62-B8D4-B713C4029578}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisitorLib", "VisitorLib\VisitorLib.csproj", "{148F50F8-70D5-462A-9C1E-F25463EF7BB4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DecoratorLib", "DecoratorLib\DecoratorLib.csproj", "{298AAC41-87D0-475E-B97C-4F9389549F3E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProxyLib", "ProxyLib\ProxyLib.csproj", "{76B2946E-1252-442D-B995-F46D4B1A3520}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -12,5 +18,17 @@ Global {97DCCECE-E259-4D62-B8D4-B713C4029578}.Debug|Any CPU.Build.0 = Debug|Any CPU {97DCCECE-E259-4D62-B8D4-B713C4029578}.Release|Any CPU.ActiveCfg = Release|Any CPU {97DCCECE-E259-4D62-B8D4-B713C4029578}.Release|Any CPU.Build.0 = Release|Any CPU + {148F50F8-70D5-462A-9C1E-F25463EF7BB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {148F50F8-70D5-462A-9C1E-F25463EF7BB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {148F50F8-70D5-462A-9C1E-F25463EF7BB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {148F50F8-70D5-462A-9C1E-F25463EF7BB4}.Release|Any CPU.Build.0 = Release|Any CPU + {298AAC41-87D0-475E-B97C-4F9389549F3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {298AAC41-87D0-475E-B97C-4F9389549F3E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {298AAC41-87D0-475E-B97C-4F9389549F3E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {298AAC41-87D0-475E-B97C-4F9389549F3E}.Release|Any CPU.Build.0 = Release|Any CPU + {76B2946E-1252-442D-B995-F46D4B1A3520}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {76B2946E-1252-442D-B995-F46D4B1A3520}.Debug|Any CPU.Build.0 = Debug|Any CPU + {76B2946E-1252-442D-B995-F46D4B1A3520}.Release|Any CPU.ActiveCfg = Release|Any CPU + {76B2946E-1252-442D-B995-F46D4B1A3520}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/DesignPatterns/Builder/Warehouse.cs b/DesignPatterns/Builder/Warehouse.cs new file mode 100644 index 0000000..6e3ff88 --- /dev/null +++ b/DesignPatterns/Builder/Warehouse.cs @@ -0,0 +1,27 @@ +namespace DesignPatterns; + +public class Warehouse(Warehouse.WarehouseBuilder warehouseBuilder) +{ + public int Capacity { get; } = warehouseBuilder.Capacity; + public List Stock { get; } = warehouseBuilder.Stock ?? []; + + public override string ToString() { + return $"Capacity: {Capacity}, Stock: {string.Join(",", Stock)}"; + } + public class WarehouseBuilder(int capacity) + { + public int Capacity { get; } = capacity; + public List? Stock { get; private set; } + public WarehouseBuilder SetStock(List stock) + { + Stock = stock; + return this; + } + public Warehouse Build() + { + var warehouse = new Warehouse(this); + return warehouse; + } + } + +} diff --git a/DesignPatterns/Decorator/ComponentDecorator.cs b/DesignPatterns/Decorator/ComponentDecorator.cs new file mode 100644 index 0000000..e56b5f8 --- /dev/null +++ b/DesignPatterns/Decorator/ComponentDecorator.cs @@ -0,0 +1,9 @@ +using DecoratorLib; + +namespace DesignPatterns.Decorator; + +public abstract class ComponentDecorator(IComponent component) : IComponent +{ + private readonly IComponent _component = component; + public abstract void Log(); +} diff --git a/DesignPatterns/Decorator/FailableComponentComponentDecorator.cs b/DesignPatterns/Decorator/FailableComponentComponentDecorator.cs new file mode 100644 index 0000000..f6c9877 --- /dev/null +++ b/DesignPatterns/Decorator/FailableComponentComponentDecorator.cs @@ -0,0 +1,22 @@ +using DecoratorLib; + +namespace DesignPatterns.Decorator; + +public class FailableComponentComponentDecorator(IComponent comp) : ComponentDecorator(comp) +{ + private readonly IComponent _comp = comp; + public bool ShouldFail { get; set; } + + public override void Log() + { + if (ShouldFail) + { + throw new Exception("FailableComponentComponentDecorator should fail"); + } + _comp.Log(); + } + public string GetLogString() + { + return "Component Log"; + } +} diff --git a/DesignPatterns/DesignPatterns.csproj b/DesignPatterns/DesignPatterns.csproj index 6c1dc92..cafd5f2 100644 --- a/DesignPatterns/DesignPatterns.csproj +++ b/DesignPatterns/DesignPatterns.csproj @@ -7,4 +7,10 @@ enable + + + + + + diff --git a/DesignPatterns/Factory/Book.cs b/DesignPatterns/Factory/Book.cs new file mode 100644 index 0000000..c7420e2 --- /dev/null +++ b/DesignPatterns/Factory/Book.cs @@ -0,0 +1,11 @@ +namespace DesignPatterns; + +sealed class Book : Product +{ + internal Book() + { + + } + public new double Price { get; set; } = 20; + public override string ToString() => "Book"; +} diff --git a/DesignPatterns/Factory/Product.cs b/DesignPatterns/Factory/Product.cs new file mode 100644 index 0000000..c9b50bc --- /dev/null +++ b/DesignPatterns/Factory/Product.cs @@ -0,0 +1,16 @@ +namespace DesignPatterns; + +public abstract class Product +{ + public double Price { get; set; } = 5; + public override string ToString() => "Product"; + public static Product FactoryMethod(string productName) + { + return productName switch + { + "Smartphone" => new Smartphone(), + "Book" => new Book(), + _ => throw new ArgumentException() + }; + } +} diff --git a/DesignPatterns/Factory/Smartphone.cs b/DesignPatterns/Factory/Smartphone.cs new file mode 100644 index 0000000..c14c7cc --- /dev/null +++ b/DesignPatterns/Factory/Smartphone.cs @@ -0,0 +1,11 @@ +namespace DesignPatterns; + +sealed class Smartphone : Product +{ + internal Smartphone() + { + + } + public new double Price { get; set; } = 300; + public override string ToString() => "Smartphone"; +} diff --git a/DesignPatterns/Program.cs b/DesignPatterns/Program.cs index 139ec4e..43b40f6 100644 --- a/DesignPatterns/Program.cs +++ b/DesignPatterns/Program.cs @@ -1,3 +1,39 @@ -// See https://aka.ms/new-console-template for more information +using DecoratorLib; +using DesignPatterns; +using DesignPatterns.Decorator; +using ProxyLib; +using VisitorLib; -Console.WriteLine("Hello, World!"); +LoggerSingleton.Instance.Logger.WriteLine("Hello World!"); +var product = Product.FactoryMethod("Smartphone"); +Console.WriteLine(product); +product = Product.FactoryMethod("Book"); +Console.WriteLine(product); +var warehouseBuilder = new Warehouse.WarehouseBuilder(12); +warehouseBuilder.SetStock(["abc", "def"]); +var warehouse = warehouseBuilder.Build(); +Console.WriteLine($"{warehouse.Capacity}, {warehouse.Stock}"); +var visitor = new LoggingVisitor(); +List shapes = +[ + new Rectangle + { + Area = 12, + }, + new Circle() + { + Radius = 5, + } +]; +shapes.ForEach(shape => shape.Accept(visitor)); +var decorator = new FailableComponentComponentDecorator(new Component()) +{ + ShouldFail = false, +}; +Console.WriteLine(decorator.GetLogString()); +decorator.Log(); +ISubject subject = new SubjectProxy +{ + CanLog = true, +}; +subject.Log(); \ No newline at end of file diff --git a/DesignPatterns/Singleton/LoggerSingleton.cs b/DesignPatterns/Singleton/LoggerSingleton.cs new file mode 100644 index 0000000..e29bea9 --- /dev/null +++ b/DesignPatterns/Singleton/LoggerSingleton.cs @@ -0,0 +1,17 @@ +namespace DesignPatterns; + +public class LoggerSingleton +{ + private static LoggerSingleton? _instance; + + public static LoggerSingleton Instance + { + get + { + _instance ??= new LoggerSingleton(); + return _instance; + } + } + + public TextWriter Logger => Console.Out; +} diff --git a/DesignPatterns/Visitor/LoggingVisitor.cs b/DesignPatterns/Visitor/LoggingVisitor.cs new file mode 100644 index 0000000..8d5caf4 --- /dev/null +++ b/DesignPatterns/Visitor/LoggingVisitor.cs @@ -0,0 +1,16 @@ +using VisitorLib; + +namespace DesignPatterns; + +public class LoggingVisitor: IShapeVisitor +{ + + public void VisitRectangle(Rectangle rectangle) + { + Console.WriteLine($"Rect, Area: {rectangle.Area}"); + } + public void VisitCircle(Circle circle) + { + Console.WriteLine($"Circle, Radius: {circle.Radius}"); + } +} diff --git a/ProxyLib/ConcreteSubject.cs b/ProxyLib/ConcreteSubject.cs new file mode 100644 index 0000000..7c775a7 --- /dev/null +++ b/ProxyLib/ConcreteSubject.cs @@ -0,0 +1,10 @@ +namespace ProxyLib; + +internal class ConcreteSubject: ISubject +{ + + public void Log() + { + Console.WriteLine("ConcreteSubject Log"); + } +} diff --git a/ProxyLib/ISubject.cs b/ProxyLib/ISubject.cs new file mode 100644 index 0000000..655e4eb --- /dev/null +++ b/ProxyLib/ISubject.cs @@ -0,0 +1,6 @@ +namespace ProxyLib; + +public interface ISubject +{ + void Log(); +} diff --git a/ProxyLib/ProxyLib.csproj b/ProxyLib/ProxyLib.csproj new file mode 100644 index 0000000..237d661 --- /dev/null +++ b/ProxyLib/ProxyLib.csproj @@ -0,0 +1,9 @@ + + + + net10.0 + enable + enable + + + diff --git a/ProxyLib/SubjectProxy.cs b/ProxyLib/SubjectProxy.cs new file mode 100644 index 0000000..f13570e --- /dev/null +++ b/ProxyLib/SubjectProxy.cs @@ -0,0 +1,13 @@ +namespace ProxyLib; + +public class SubjectProxy : ISubject +{ + public bool CanLog { get; set; } + private readonly ISubject _subject = new ConcreteSubject(); + + public void Log() + { + if (!CanLog) return; + _subject.Log(); + } +} diff --git a/VisitorLib/Circle.cs b/VisitorLib/Circle.cs new file mode 100644 index 0000000..cf03f21 --- /dev/null +++ b/VisitorLib/Circle.cs @@ -0,0 +1,10 @@ +namespace VisitorLib; + +public class Circle: Shape +{ + public int Radius { get; set; } + public override void Accept(IShapeVisitor visitor) + { + visitor.VisitCircle(this); + } +} diff --git a/VisitorLib/IShapeVisitor.cs b/VisitorLib/IShapeVisitor.cs new file mode 100644 index 0000000..7a178fb --- /dev/null +++ b/VisitorLib/IShapeVisitor.cs @@ -0,0 +1,7 @@ +namespace VisitorLib; + +public interface IShapeVisitor +{ + void VisitRectangle(Rectangle rectangle); + void VisitCircle(Circle rectangle); +} diff --git a/VisitorLib/Rectangle.cs b/VisitorLib/Rectangle.cs new file mode 100644 index 0000000..361a8f2 --- /dev/null +++ b/VisitorLib/Rectangle.cs @@ -0,0 +1,10 @@ +namespace VisitorLib; + +public class Rectangle: Shape +{ + public int Area { get; set; } + public override void Accept(IShapeVisitor visitor) + { + visitor.VisitRectangle(this); + } +} diff --git a/VisitorLib/Shape.cs b/VisitorLib/Shape.cs new file mode 100644 index 0000000..76d90ba --- /dev/null +++ b/VisitorLib/Shape.cs @@ -0,0 +1,6 @@ +namespace VisitorLib; + +public abstract class Shape +{ + public abstract void Accept(IShapeVisitor visitor); +} diff --git a/VisitorLib/VisitorLib.csproj b/VisitorLib/VisitorLib.csproj new file mode 100644 index 0000000..eff83a4 --- /dev/null +++ b/VisitorLib/VisitorLib.csproj @@ -0,0 +1,10 @@ + + + + net10.0 + enable + enable + VisitorLib + + +