Home > OS >  Decorator design pattern with generic repository
Decorator design pattern with generic repository

Time:11-16

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

  • Related