Add Design Patterns

This commit is contained in:
2026-01-20 10:30:21 +01:00
parent 4a83bd3d5a
commit b9e8eb590c
24 changed files with 298 additions and 3 deletions

3
.gitignore vendored
View File

@@ -3,4 +3,5 @@ obj/
/packages/
riderModule.iml
/_ReSharper.Caches/
.idea/
.idea/
*.user

View File

@@ -0,0 +1,9 @@
namespace DecoratorLib;
public class Component : IComponent
{
public void Log()
{
Console.WriteLine("Component Log");
}
}

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,6 @@
namespace DecoratorLib;
public interface IComponent
{
void Log();
}

View File

@@ -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

View File

@@ -0,0 +1,27 @@
namespace DesignPatterns;
public class Warehouse(Warehouse.WarehouseBuilder warehouseBuilder)
{
public int Capacity { get; } = warehouseBuilder.Capacity;
public List<string> 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<string>? Stock { get; private set; }
public WarehouseBuilder SetStock(List<string> stock)
{
Stock = stock;
return this;
}
public Warehouse Build()
{
var warehouse = new Warehouse(this);
return warehouse;
}
}
}

View File

@@ -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();
}

View File

@@ -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";
}
}

View File

@@ -7,4 +7,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\DecoratorLib\DecoratorLib.csproj" />
<ProjectReference Include="..\ProxyLib\ProxyLib.csproj" />
<ProjectReference Include="..\VisitorLib\VisitorLib.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,11 @@
namespace DesignPatterns;
sealed class Book : Product
{
internal Book()
{
}
public new double Price { get; set; } = 20;
public override string ToString() => "Book";
}

View File

@@ -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()
};
}
}

View File

@@ -0,0 +1,11 @@
namespace DesignPatterns;
sealed class Smartphone : Product
{
internal Smartphone()
{
}
public new double Price { get; set; } = 300;
public override string ToString() => "Smartphone";
}

View File

@@ -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<Shape> 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();

View File

@@ -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;
}

View File

@@ -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}");
}
}

View File

@@ -0,0 +1,10 @@
namespace ProxyLib;
internal class ConcreteSubject: ISubject
{
public void Log()
{
Console.WriteLine("ConcreteSubject Log");
}
}

6
ProxyLib/ISubject.cs Normal file
View File

@@ -0,0 +1,6 @@
namespace ProxyLib;
public interface ISubject
{
void Log();
}

9
ProxyLib/ProxyLib.csproj Normal file
View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

13
ProxyLib/SubjectProxy.cs Normal file
View File

@@ -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();
}
}

10
VisitorLib/Circle.cs Normal file
View File

@@ -0,0 +1,10 @@
namespace VisitorLib;
public class Circle: Shape
{
public int Radius { get; set; }
public override void Accept(IShapeVisitor visitor)
{
visitor.VisitCircle(this);
}
}

View File

@@ -0,0 +1,7 @@
namespace VisitorLib;
public interface IShapeVisitor
{
void VisitRectangle(Rectangle rectangle);
void VisitCircle(Circle rectangle);
}

10
VisitorLib/Rectangle.cs Normal file
View File

@@ -0,0 +1,10 @@
namespace VisitorLib;
public class Rectangle: Shape
{
public int Area { get; set; }
public override void Accept(IShapeVisitor visitor)
{
visitor.VisitRectangle(this);
}
}

6
VisitorLib/Shape.cs Normal file
View File

@@ -0,0 +1,6 @@
namespace VisitorLib;
public abstract class Shape
{
public abstract void Accept(IShapeVisitor visitor);
}

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>VisitorLib</RootNamespace>
</PropertyGroup>
</Project>