在下面的示例代码中,我有一个接口
IService
,它只有一个用户需要实现的方法GetDescriptors
。
我还添加了常见查询的辅助方法,以便更轻松地使用
IService
。我用两种不同的方式展示了这一点,界面本身的方法,然后也通过扩展方法。
虽然这有效,但想象一下,无论出于何种原因,
GetDescriptorsByGroup
实际上是一个昂贵的调用,而不是每次调用时计算它的值,我们希望惰性地评估它并缓存结果以在将来的调用中返回(结果永远不会改变)。
有什么方法可以实现这一点,而不必在每个实现
GetDescriptorsByGroup
的类上实现IService
?
我有很多类实现
IService
,包括 Mocks,因此必须实现 GetDescriptorsByGroup
的重复代码将不太理想。我曾考虑过一个基类,..但是这对于模拟不起作用。
public class Descriptor
{
public string Name { get; }
public string Group { get; }
public int Count { get; }
public string[] Dependencies { get; }
public Descriptor(string name, string group, int count, string[] dependencies)
{
Name = name;
Group = group;
Count = count;
Dependencies = dependencies;
}
}
public interface IService
{
IReadOnlyList<Descriptor> GetDescriptors();
// helpers
IEnumerable<Descriptor> GetDescriptorsByName(string name) => GetDescriptors().Where(e => e.Name == name);
IEnumerable<Descriptor> GetDescriptorsByGroup(string group) => GetDescriptors().Where(e => e.Group == group);
}
// more helpers
public static class IServiceExtensions
{
public static IEnumerable<Descriptor> GetDescriptorsCount(this IService service, int count) => service.GetDescriptors().Where(e => e.Count == count);
public static IEnumerable<string> GetAllDependencies(this IService service) => service.GetDescriptors().SelectMany(e => e.Dependencies);
}
public class ServiceA : IService
{
private readonly List<Descriptor> _descriptors;
public ServiceA()
{
// compute descriptors here ...
_descriptors = new List<Descriptor>();
}
public IReadOnlyList<Descriptor> GetDescriptors() => _descriptors;
}
public class ServiceB : IService
{
private readonly List<Descriptor> _descriptors;
public ServiceB()
{
// compute descriptors here ...
_descriptors = new List<Descriptor>();
}
public IReadOnlyList<Descriptor> GetDescriptors() => _descriptors;
}
internal class Program
{
static void Main(string[] args)
{
IService service = new ServiceA();
var x = service.GetDescriptorsByName("A");
var y = service.GetAllDependencies();
}
}
你能做的是装饰者:
public sealed class CachingService : IService
{
private readonly IService _valueSource;
private readonly SomeCacheImpl<object key, Lazy<IReadOnlyList<Descriptor>>> _cache;
private readonly object _key = new(); // In this case, there is only one key...
public CachingService(IService valueSource)
{
_valueSource = valueSource;
_cache = new(); // Or inject ...
}
public IReadOnlyList<Descriptor> GetDescriptors()
=> _cache.GetOrAdd(_key, _key => new Lazy<IReadOnlyList<Descriptor>>(() => _valueSource.GetDescriptors()).Value;
}
然后您可以注入而不是具体的 IService 实现:
static void Main(string[] args)
{
IService service = new CachingService(new ServiceA());
var x = service.GetDescriptorsByName("A");
var y = service.GetAllDependencies();
}