实现Scrutor,但仅在几种方法上扩展缓存

问题描述

我打算实施scrutor

public interface ICustomersRepository
{
   Task<CustomerDto> GetCustomerAsync(Guid customerId);
   Task<bool> SaveCustomer(CustomerDto customer);
}

public class CustomersRepository : ICustomersRepository
{
   private readonly List<CustomerDto> _customers = new List<CustomerDto>
   {
      new CustomerDto{Id = Guid.Parse("64fa643f-2d35-46e7-b3f8-31fa673d719b"),Name = "Nick Chapsas"},new CustomerDto{Id = Guid.Parse("fc7cdfc4-f407-4955-acbe-98c666ee51a2"),Name = "John Doe"},new CustomerDto{Id = Guid.Parse("a46ac8f4-2ecd-43bf-a9e6-e557b9af1d6e"),Name = "Sam McRandom"}
   };
        
   public Task<CustomerDto> GetCustomerAsync(Guid customerId)
   {
      return Task.Fromresult(_customers.SingleOrDefault(x => x.Id == customerId));
   }

   public Task<bool> SaveCustomer(CustomerDto customer)
   {
       return "Save Customer here and return bool";
   }
}

实施缓存的存储库:

public class CachedCustomersRepository : ICustomersRepository
    {
        private readonly ICustomersRepository _customersRepository; //CustomersRepository
        private readonly ConcurrentDictionary<Guid,CustomerDto> _cache = new ConcurrentDictionary<Guid,CustomerDto>();
        
        public CachedCustomersRepository(ICustomersRepository customersRepository)
        {
            _customersRepository = customersRepository;
        }
        
        public async Task<CustomerDto> GetCustomerAsync(Guid customerId)
        {
            if (_cache.ContainsKey(customerId))
            {
                return _cache[customerId];
            }

            var customer = await _customersRepository.GetCustomerAsync(customerId);
            _cache.TryAdd(customerId,customer);
            return customer;
        }
    }

这就是我如何做DI:

public void ConfigureServices(IServiceCollection services)
{
   services.AddControllers();

   services.AddSingleton<ICustomersRepository,CustomersRepository>();
   services.Decorate<ICustomersRepository,CachedCustomersRepository>();
}

我看到的问题是ICustomerRepository同时具有GetCustomerAsync和SaveCustomer方法,我可以在CacheCustomerRepository中实现ICustomerRepository并定义GetCustomerAsync方法,但是如何忽略SaveCustomer,因为它不能作为CacheCustomerRepository类中的缓存方法。如果我没有在CacheCustomerRepository中定义该方法,由于缺少接口实现,我将得到错误,如何以干净的方式实现scrutor,有没有一种方法可以实现仅需要缓存的几种方法,而其余方法可以放在主要方法中存储库类?

我可以想到只在CacheCustomersRepository中包含骨架以保存方法,但这是一种干净的方法,并且如果我的CustomerRepository有50种方法,其中只有5种方法需要缓存实现,那么这是非常多余的,不是很好将所有框架方法放入缓存存储库的方法

我们如何以干净的方式实现scrutor?有什么建议吗?

解决方法

要解决您的特定问题,不需要处理缓存的方法,只需将其委托给装饰的对象即可,即

public class CachedCustomersRepository : ICustomersRepository
{
    private readonly ICustomersRepository _customersRepository; //CustomersRepository
    private readonly ConcurrentDictionary<Guid,CustomerDto> _cache = new ConcurrentDictionary<Guid,CustomerDto>();
        
    public CachedCustomersRepository(ICustomersRepository customersRepository)
    {
        _customersRepository = customersRepository;
    }
        
    public async Task<CustomerDto> GetCustomerAsync(Guid customerId)
    {
        if (_cache.ContainsKey(customerId))
        {
            return _cache[customerId];
        }

        var customer = await _customersRepository.GetCustomerAsync(customerId);
        _cache.TryAdd(customerId,customer);
        return customer;
    }

    // No need to cache anything,just delegate it,although you might need to
    // invalidate the cache if a cached customer is saved
    public Task<bool> SaveCustomer(CustomerDto customer) => 
        _customersRepository.SaveCustomer(customer);
}

关于在您的存储库有50种方法的情况下如何解决此问题的更广泛的问题,而您对项目的其余部分一无所知,我的第一个直觉是,现有设计可能还有一些改进的空间。这种假设的情况可能是练习interface seggregation principle的好机会。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...