Roadmap › Design Patterns (GoF + Enterprise) in C# › Module: Structural Patterns
Lessons in this course (18)
7. Decorator
Intermediate★ Must knowLesson 7 of 18
Add behaviour to an object dynamically by wrapping it, without changing its class. Wrappers implement the same interface.
csharp
public interface IProductRepository { Task<Product?> GetAsync(int id); }
public class SqlProductRepository(AppDbContext db) : IProductRepository
{
public Task<Product?> GetAsync(int id) => db.Products.FindAsync(id).AsTask();
}
public class CachedProductRepository(IProductRepository inner, IMemoryCache cache) : IProductRepository
{
public Task<Product?> GetAsync(int id) =>
cache.GetOrCreateAsync($"product:{id}", e => { e.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5); return inner.GetAsync(id); });
}
// With Scrutor:
builder.Services.AddScoped<IProductRepository, SqlProductRepository>();
builder.Services.Decorate<IProductRepository, CachedProductRepository>();.NET examples: Stream wrappers (BufferedStream, GZipStream, CryptoStream), DelegatingHandler in HttpClient.