我有很多类实现这样的接口:
public interface IProcessor
{
Foo Foo { get; set; }
int Process();
}
我有一家生产这些产品的工厂,而且我不知道会提前生产多少产品。问题是,检索必要的Foo
对象非常昂贵,并且在IProcessor
调用Process
之前,该属性实际上并未在public IProcessor CreateProcessor(int fooId)
{
Foo foo = this.Context.GetFoo(fooId);
return new ImplementedProcessor { Foo = foo };
}
中使用。
所以如果我的工厂有这样的方法:
GetFoo
我每次都要打电话给public IProcessor CreateProcessor(int fooId)
{
this.CurrentlyTrackedFooIds.Add(fooId);
return new ImplementedProcessor { Foo = what??? };
}
。我真正喜欢的是这样的:
ImplementedProcessor
我们的想法是,在Foo
需要Process
进行this.Context.GetAllFoosAtOnceCheaply(this.CurrentlyTrackedFooIds);
方法之前,它会排队等待,以便可以像以下那样大量检索:
IProcessor
是否有任何延迟加载模式可以帮助这样的事情?我可以完全控制整个项目,因此我不受现有IProcessorFactory
或{{1}}接口的限制。我可以想办法做到这一点(可能是某种代表吗?),但是它们中没有一个看起来很干净,我想通过在项目中拥有一百万个不同的实现来避免这种事情失控。任何帮助将不胜感激!
答案 0 :(得分:4)
因此,有两种类型可以让我们的生活超级变得简单。第一个是Lazy
。构造Lazy
对象时,为其提供一个返回值的函数。然后,当你要求Lazy
的值时,它会启动函数(如果它没有启动),如果它没有完成则等待函数,然后返回值。它从不调用该函数两次。如果永远不会要求Value
,它甚至不会关闭该功能一次。
然后我们可以创建ConcurrentDictionary
个Lazy
个对象,这样我们就可以确保获得我们拥有的任何现有Lazy
个对象。请注意,它的GetOrAdd
方法显然是原子的。我们可以确定字典不会用另一个字体覆盖现有的Lazy
对象;它要么返回现有的,要么设置一个新的。这意味着我们永远不会在代表相同ID的两个不同Value
对象上调用Lazy
。
毕竟,编码并不多:
private ConcurrentDictionary<int, Lazy<IProcessor>> lookup =
new ConcurrentDictionary<int, Lazy<IProcessor>>();
public IProcessor CreateProcessor(int fooId)
{
var lazy = lookup.GetOrAdd(fooId, new Lazy<IProcessor>(Context.GetFoo));
return new ImplementedProcessor { Foo = lazy.Value };
}
答案 1 :(得分:3)
从.NET 4.0开始,框架为此提供了Lazy<T>
类:
public interface IProcessor {
Foo Foo { get; }
int Process();
}
internal class ImplementedProcessor {
internal Lazy<Foo> LazyFoo {get;set;}
public Foo Foo {
get {
return LazyFoo.Value;
}
}
public int Process() {
...
}
}
public IProcessor CreateProcessor(int fooId) {
return new ImplementedProcessor {
LazyFoo = () => this.Context.GetFoo(fooId)
};
}
然而,这不会批量检索Foo
- 该过程将逐个进行。只有在您的某些Process()
项目永远不会调用ImplementedProcessor
时,您才会节省一些时间。
为此,您需要在检索到第一个Foo
时创建一个懒惰初始化的缓存,并保留其余Foo
以获取缓存值。不过,Lazy<T>
不适合这个。在调用IProcessor
之前,请考虑向fooId
添加方法以获取缓存所需的Process
,并添加一个检索所有感兴趣的ID的类。