Skip to content

Commit d1aa3ea

Browse files
committed
Update the specification pattern example
1 parent e84bae9 commit d1aa3ea

File tree

9 files changed

+31
-38
lines changed

9 files changed

+31
-38
lines changed

src/AdditionalPatterns/Specification/ProductSpecification/Domain/Entity.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ protected Entity()
77
Id = Guid.NewGuid();
88
}
99

10-
public Guid Id { get; protected set; }
10+
public Guid Id { get; init; }
1111

12-
public static bool operator ==(Entity a, Entity b)
12+
public static bool operator ==(Entity? a, Entity? b)
1313
{
1414
if (a is null && b is null)
1515
{
@@ -28,9 +28,7 @@ protected Entity()
2828

2929
public override bool Equals(object obj)
3030
{
31-
var other = obj as Entity;
32-
33-
if (other is null)
31+
if (obj is not Entity other)
3432
{
3533
return false;
3634
}

src/AdditionalPatterns/Specification/ProductSpecification/Domain/Product.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@
22

33
public class Product : Entity
44
{
5-
public Product(
6-
string title,
7-
ProductCategory category,
8-
decimal price,
9-
double rating,
10-
DateTime launchDate)
5+
public Product(string title, ProductCategory category, decimal price, double rating, DateTime launchDate)
116
: base()
127
{
138
Title = title;
@@ -18,13 +13,9 @@ public Product(
1813
}
1914

2015
public string Title { get; set; }
21-
2216
public ProductCategory Category { get; set; }
23-
2417
public decimal Price { get; set; }
25-
2618
public double Rating { get; set; }
27-
2819
public DateTime LaunchDate { get; set; }
2920

3021
public override string ToString() =>

src/AdditionalPatterns/Specification/ProductSpecification/Domain/ProductCategory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ public enum ProductCategory
88
Handmade,
99
SportsAndOutdoors,
1010
ToysAndGames,
11-
}
11+
}

src/AdditionalPatterns/Specification/ProductSpecification/Executor.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,28 @@ public override void Execute()
1212
{
1313
var productRepository = new ProductRepository();
1414

15-
var recentlyLaunched = new RecentlyLaunchedProductSpecification();
16-
1715
var cheap = new CheapProductSpecification();
1816
var topRated = new TopRatedProductSpecification();
19-
var specification = cheap.And(topRated);
17+
var cheapAndTopRated = cheap.And(topRated);
2018

2119
Console.WriteLine("Searching for cheap and top rated products...");
22-
var products = productRepository.Find(specification);
20+
var products = productRepository.Find(cheapAndTopRated);
21+
22+
var recentlyLaunched = new RecentlyLaunchedProductSpecification();
23+
var ordinalNumber = 1;
2324

2425
foreach (var product in products)
2526
{
2627
Console.WriteLine(Environment.NewLine);
27-
Console.WriteLine(product);
28+
Console.WriteLine($"{ordinalNumber}) {product}");
2829

29-
// Specifications could be used in different parts of the application
30+
// Specifications could be used in different parts of the application.
3031
if (recentlyLaunched.IsSatisfiedBy(product))
3132
{
32-
Console.WriteLine($"Sending promotional email about recently launched product '{product.Title}'");
33+
Console.WriteLine($"Sending promotional email about recently launched product '{product.Title}'...");
3334
}
35+
36+
ordinalNumber++;
3437
}
3538
}
36-
}
39+
}

src/AdditionalPatterns/Specification/ProductSpecification/Infrastructure/ProductRepository.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,19 @@ public ProductRepository()
1111
{
1212
_products = new List<Product>
1313
{
14-
new Product("Designing Data-Intensive Applications", ProductCategory.Books, 44.50m, 4.7, new DateTime(2017, 4, 18)),
15-
new Product("Kindle Paperwhite", ProductCategory.Electronics, 84.99m, 4.6, new DateTime(2018, 1, 1)),
16-
new Product("USB Hub", ProductCategory.Electronics, 8.99m, 4.7, DateTime.Today.AddDays(-2)),
17-
new Product("Bed Sheet Set", ProductCategory.HomeAndKitchen, 35.99m, 4.2, new DateTime(2018, 8, 18)),
18-
new Product("UNO Card Game", ProductCategory.ToysAndGames, 9.99m, 4.9, new DateTime(2014, 4, 14)),
14+
new("Designing Data-Intensive Applications", ProductCategory.Books, 44.50m, 4.7, new DateTime(2017, 4, 18)),
15+
new("Kindle Paperwhite", ProductCategory.Electronics, 84.99m, 4.6, new DateTime(2018, 1, 1)),
16+
new("USB Hub", ProductCategory.Electronics, 8.99m, 4.7, DateTime.Today.AddDays(-2)),
17+
new("Bed Sheet Set", ProductCategory.HomeAndKitchen, 35.99m, 4.2, new DateTime(2018, 8, 18)),
18+
new("UNO Card Game", ProductCategory.ToysAndGames, 9.99m, 4.9, new DateTime(2014, 4, 14)),
1919
};
2020
}
2121

2222
public IReadOnlyList<Product> Find(Specification<Product> specification, int page = 0, int pageSize = 100) =>
23-
_products.AsQueryable()
23+
_products
24+
.AsQueryable()
2425
.Where(specification.ToExpression())
2526
.Skip(page * pageSize)
2627
.Take(pageSize)
2728
.ToList();
28-
}
29+
}

src/AdditionalPatterns/Specification/ProductSpecification/Specifications/Common/AndSpecification.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ public override Expression<Func<T, bool>> ToExpression()
2626

2727
return finalExpression;
2828
}
29-
}
29+
}

src/AdditionalPatterns/Specification/ProductSpecification/Specifications/Common/OrSpecification.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ public override Expression<Func<T, bool>> ToExpression()
2626

2727
return finalExpression;
2828
}
29-
}
29+
}

src/AdditionalPatterns/Specification/ProductSpecification/Specifications/Common/Specification.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ namespace ProductSpecification.Specifications.Common;
77
/// into a single unit - specification, and reuse it in different parts of the code base.
88
/// There are 3 main use cases for the specification pattern:
99
/// 1) Looking up data in the database - finding records that match arbitrary specification.
10-
/// 2) Validating objects in the memory - checking whether object we retrieved or created fits arbitrary specification.
11-
/// 3) Creating a new instance that matches the criteria.
10+
/// 2) Validating objects in the memory - checking whether an object we retrieved or created fits arbitrary specification.
11+
/// 3) Creating a new instance that matches a criteria.
1212
/// For more details see: https://enterprisecraftsmanship.com/posts/specification-pattern-c-implementation/
1313
/// </summary>
1414
/// <typeparam name="T">Entity type.</typeparam>
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using System.Linq.Expressions;
2-
using ProductSpecification.Domain;
1+
using ProductSpecification.Domain;
32
using ProductSpecification.Specifications.Common;
3+
using System.Linq.Expressions;
44

55
namespace ProductSpecification.Specifications;
66

@@ -9,4 +9,4 @@ public class RecentlyLaunchedProductSpecification : Specification<Product>
99
public override Expression<Func<Product, bool>> ToExpression() =>
1010
// Products are considered as recently launched if they are launched in the last 7 days
1111
product => DateTime.Today.AddDays(-7) <= product.LaunchDate;
12-
}
12+
}

0 commit comments

Comments
 (0)