Skip to content

Commit 4b061ee

Browse files
committed
Add Builder Pattern implementation and tests
1 parent 2867969 commit 4b061ee

File tree

5 files changed

+151
-9
lines changed

5 files changed

+151
-9
lines changed

DesignPatterns/Builder/House.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace DesignPatterns.Builder;
2+
3+
public sealed class House
4+
{
5+
public int Rooms { get; }
6+
public int Windows { get; }
7+
public bool HasGarage { get; }
8+
public string Address { get; }
9+
10+
public House(int rooms, int windows, bool hasGarage, string address)
11+
{
12+
if (rooms < 0) throw new ArgumentOutOfRangeException(nameof(rooms));
13+
if (windows < 0) throw new ArgumentOutOfRangeException(nameof(windows));
14+
Address = address ?? string.Empty;
15+
Rooms = rooms;
16+
Windows = windows;
17+
HasGarage = hasGarage;
18+
}
19+
20+
public override string ToString() => $"House: {Rooms} rooms, {Windows} windows, Garage: {HasGarage}, Address: {Address}";
21+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
namespace DesignPatterns.Builder;
2+
3+
public class HouseBuilder
4+
{
5+
private int _rooms;
6+
private int _windows;
7+
private bool _hasGarage;
8+
private string _address = string.Empty;
9+
10+
public HouseBuilder WithRooms(int rooms)
11+
{
12+
_rooms = rooms;
13+
return this;
14+
}
15+
16+
public HouseBuilder WithWindows(int windows)
17+
{
18+
_windows = windows;
19+
return this;
20+
}
21+
22+
public HouseBuilder WithGarage(bool hasGarage = true)
23+
{
24+
_hasGarage = hasGarage;
25+
return this;
26+
}
27+
28+
public HouseBuilder AtAddress(string address)
29+
{
30+
_address = address ?? string.Empty;
31+
return this;
32+
}
33+
34+
public House Build()
35+
{
36+
return new House(_rooms, _windows, _hasGarage, _address);
37+
}
38+
}

DesignPatterns/Program.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using DesignPatterns.Factories;
22
using DesignPatterns.Singleton;
3+
using DesignPatterns.Builder;
34

45
Console.WriteLine("Factory pattern demo:");
56

@@ -11,14 +12,24 @@
1112
Console.WriteLine(square.Draw());
1213
Console.WriteLine(rect.Draw());
1314

15+
// Builder demo
16+
var house = new HouseBuilder()
17+
.WithRooms(3)
18+
.WithWindows(5)
19+
.WithGarage()
20+
.AtAddress("123 Main St")
21+
.Build();
22+
23+
Console.WriteLine();
24+
Console.WriteLine("Builder pattern demo:");
25+
Console.WriteLine(house.ToString());
26+
1427
// Singleton demo
1528
Logger.Instance.Clear();
16-
Logger.Instance.Log("Application started");
17-
Logger.Instance.Log(circle.Draw());
18-
Logger.Instance.Log(square.Draw());
19-
Logger.Instance.Log(rect.Draw());
20-
Logger.Instance.Log("Application finished");
29+
Logger.Instance.Log("Singleton started");
30+
Logger.Instance.Log("Singleton finished");
2131

32+
Console.WriteLine();
2233
Console.WriteLine("Logged messages:");
2334
foreach (var msg in Logger.Instance.Messages)
2435
{

README.md

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,49 @@ Design Patterns Examples
33
This solution demonstrates simple design pattern examples in C# targeting .NET 10 (C# 14).
44

55
Projects
6-
- `DesignPatterns` - Console demo showing Factory and Singleton patterns.
6+
- `DesignPatterns` - Console demo showing Factory, Singleton, and Builder patterns.
77
- Factory implementation: `DesignPatterns/Factories`
88
- Singleton implementation: `DesignPatterns/Singleton/Logger.cs`
9-
- `Tests` - xUnit tests covering the factory and singleton examples.
9+
- Builder implementation: `DesignPatterns/Builder/HouseBuilder.cs` and `DesignPatterns/Builder/House.cs`
10+
- `Tests` - xUnit tests covering the examples.
11+
12+
Included patterns and brief docs
13+
14+
- Factory Pattern
15+
- Purpose: Encapsulates object creation and returns different concrete implementations via a common interface.
16+
- Example: `DesignPatterns/Factories/ShapeFactory.cs` creates `Circle`, `Square`, or `Rectangle` based on `ShapeType`.
17+
18+
- Singleton Pattern
19+
- Purpose: Ensures a class has only one instance and provides a global point of access.
20+
- Example: `DesignPatterns/Singleton/Logger.cs` — thread-safe singleton using `System.Lazy<T>` and `System.Collections.Concurrent.ConcurrentQueue<string>` to store log messages.
21+
- Usage snippet:
22+
23+
```csharp
24+
var logger = Logger.Instance;
25+
logger.Clear();
26+
logger.Log("Application started");
27+
foreach (var msg in Logger.Instance.Messages) Console.WriteLine(msg);
28+
```
29+
30+
- Builder Pattern
31+
- Purpose: Separates the construction of a complex object from its representation, providing a fluent API for step-by-step creation.
32+
- Example: `DesignPatterns/Builder/HouseBuilder.cs` builds immutable `House` instances from `DesignPatterns/Builder/House.cs`.
33+
- Usage snippet:
34+
35+
```csharp
36+
var house = new HouseBuilder()
37+
.WithRooms(3)
38+
.WithWindows(5)
39+
.WithGarage()
40+
.AtAddress("123 Main St")
41+
.Build();
42+
```
43+
44+
Tests
45+
- Tests are written with xUnit in the `Tests` project.
46+
- Factory tests: `Tests/ShapeFactoryTests.cs`
47+
- Singleton tests: `Tests/SingletonTests.cs`
48+
- Builder tests: `Tests/BuilderTests.cs`
1049

1150
Requirements
1251
- .NET 10 SDK
@@ -17,5 +56,5 @@ Common commands
1756
- Run tests: `dotnet test`
1857

1958
Notes
20-
- The `Logger` singleton is thread-safe and uses `System.Lazy<T>` with a `ConcurrentQueue<string>` to store messages.
21-
- Tests are located in the `Tests` project; see `Tests/ShapeFactoryTests.cs` and `Tests/SingletonTests.cs`.
59+
- The examples are intentionally small to demonstrate the patterns and are suitable as learning references.
60+
- The `Logger` singleton is implemented to be safe for concurrent use in tests and examples.

Tests/BuilderTests.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using DesignPatterns.Builder;
2+
3+
namespace Tests;
4+
5+
public class BuilderTests
6+
{
7+
[Fact]
8+
public void HouseBuilder_BuildsHouseWithSpecifiedProperties()
9+
{
10+
var house = new HouseBuilder()
11+
.WithRooms(3)
12+
.WithWindows(5)
13+
.WithGarage()
14+
.AtAddress("123 Main St")
15+
.Build();
16+
17+
Assert.Equal(3, house.Rooms);
18+
Assert.Equal(5, house.Windows);
19+
Assert.True(house.HasGarage);
20+
Assert.Equal("123 Main St", house.Address);
21+
}
22+
23+
[Fact]
24+
public void HouseBuilder_DefaultsWhenNotSpecified()
25+
{
26+
var house = new HouseBuilder().Build();
27+
28+
Assert.Equal(0, house.Rooms);
29+
Assert.Equal(0, house.Windows);
30+
Assert.False(house.HasGarage);
31+
Assert.Equal(string.Empty, house.Address);
32+
}
33+
}

0 commit comments

Comments
 (0)