I have been looking at the decorator design pattern (I am new to the subject of design patterns).
I am already using BaseRepository pattern. But I want to use some cache too.
Below sample is just a dump example.
So I have IGenericRepository interface and the implementation to it.
public interface IGenericRepository<T> where T : class
{
T GetById(int id);
IEnumerable<T> GetAll();
Task<T> GetByIdAsync(int id);
T Add(T entity);
void AddRange(IEnumerable<T> entities);
Task<T> AddAsync(T entity);
Task AddRangeAsync(IEnumerable<T> entities);
void Remove(T entity);
void RemoveRange(IEnumerable<T> entities);
int SaveChanges();
Task<int> SaveChangesAsync();
}
Then I created a custom repository for example IBlogRepository
public interface IBlogRepository : IBaseRepository<Blog>
{
public Task<Blog> GetBlogsByCreatorAsync(int creatorId);
}
With the implemantation of BlogRepository
public class BlogRepository : BaseRepository<Blog>, IBlogRepository
{
public BlogRepository(DbContext db) : base(db)
{
}
public Task<Blog> GetBlogsByCreatorAsync(int creatorId) =>
db.Blogs.Where(b => b.CreatorId == creatorId)
.ToListAsync();
}
I thought this is cool, then I realised I need to improve my "speed". I am starting use IMemoryCache, but in Repository code like below.
public class BlogRepository : BaseRepository<Blog>, IBlogRepository
{
public BlogRepository(DbContext db, IMemoryCache cache) : base(db)
{
}
public Task<Blog> GetBlogsByCreatorAsync(int creatorId)
{
// if in cache else go to db
}
}
Then I met with Decorate pattern and I thought why not, I started to use it, but I am struggling now. I created CachedBlogRepository which is implement IBlogRepository, but when I asked to VS implement all interface method...
public class CachedBlogRepository : IBlogRepository
{
//All BaseRepository methods appeared here...
//But I want cache only the GetBlogsByCreatorAsync method
}
So what is the best practice here? Do I missing something or did I something wrong?
CodePudding user response:
First I don't understand this part:
BlogRepository : BaseRepository, IBlogRepository
shouldn't it be just:
BlogRepository : IBlogRepository?
Now when it comes for the Decorator Pattern I would have done this:
public interface IGenericRepository<T> where T : class
{
T GetById(int id);
IEnumerable<T> GetAll();
Task<T> GetByIdAsync(int id);
T Add(T entity);
void AddRange(IEnumerable<T> entities);
Task<T> AddAsync(T entity);
Task AddRangeAsync(IEnumerable<T> entities);
void Remove(T entity);
void RemoveRange(IEnumerable<T> entities);
int SaveChanges();
Task<int> SaveChangesAsync()
}
(Component)
public class BlogRepository : BaseRepository<Blog>, IBlogRepository
{
public BlogRepository(DbContext db) : base(db)
{
}
public Task<Blog> GetBlogsByCreatorAsync(int creatorId) =>
db.Blogs.Where(b => b.CreatorId == creatorId)
.ToListAsync();
}
(Concrete Component)
abstract class Decorator : IGenericRepository<T>
{
protected IGenerecRepository _repository;
public Decorator( IGenerecRepository repository)
{
this._repository = repository;
}
public override Task<Blog> GetBlogsByCreatorAsync()
{
if (this._repository != null)
{
return this._repository.GetBlogsByCreatorAsync();
}
else
{
return string.Empty;
}
}
}
(Base Decorator)
class CacheDecorator : Decorator
{
public CacheDecorator(IGenericRepository repo) : base(repo)
{
}
public override Task<Blog> GetBlogsByCreatorAsync()
{
//cache behavior
}
}
Uasage:
BlogRepository _basicRepo = new BlogRepository();
CacheDecorator _cacheDecorator = new CacheDecorator(_basicRepo);
_cacheDecorator.GetBlogsByCreatorAsync(creatorId);
Decorator Pattern adds behavior to the main basic behavior. It needs a wrappee (the basic component) to wrap new behavior around it.
CodePudding user response:
It looks like it is a place where CachedRepository pattern can be used.
I highly recommend you to read this beatuiful article about Building a CachedRepository in ASPNET Core
So after applying CachedRepository pattern would look like this:
public List<Blog> GetBlogsByCreatorAsync(int id)
{
string key = MyModelCacheKey "-" id;
return _cache.GetOrCreate(key, entry =>
{
entry.SetOptions(cacheOptions);
return _repository.GetBlogsByCreatorAsync(id);
});
}
You can see source code at gihub