使用DI容器(在这种情况下,Ninject
)是可能的 - 或者更确切地说,明智在整个应用程序生命周期内缓存一个经常使用的对象(或者至少直到它是刷新的)?
举个例子,说我有一个Template
。有许多Template
个对象,但每个用户将至少继承最低级别的对象。这是不可变的,如果不更新连接到它的所有东西,它将永远不会改变(因此它只会根据管理需求而改变,永远不会基于用户输入)。对于我知道不会改变的信息,一遍又一遍地查询数据库似乎是愚蠢的。
缓存最好是在我的IoC容器中完成,还是应该将其外包给其他东西?
我已将ISessionFactory
(nHibernate
)存储为单身人士。但这有点不同,因为它不包括对数据库的查询,只包括打开和关闭ISession
对象的后端。
所以基本上我会做这样的事情......
static class Immutable
{
[Inject]
public IRepository<Template> TemplateRepository { get; set; }
public static ITemplate Template { get; set; }
public void Initialize()
{
if(Immutable.Template == null)
{
Immutable.Template = TemplateRepository.Retrieve(1); // obviously better logic here.
}
}
class TemplateModule : Module
{
public void Load()
{
Bind<ITemplate>().ToMethod(() => Immutable.Initialize())InSingletonScope();
}
}
这是一种糟糕的做法吗?如果是这样,任何人都可以推荐一个更聪明的人吗?
答案 0 :(得分:2)
我通常会避免在代码中使用static
ness和null-checking - 默认情况下创建没有单例连接的普通类,并通过容器将该方面放在顶层。同上,不再依赖财产注入 - 除非你别无选择,否则注射总是更好
即:
class TemplateManager
{
readonly IRepository<Template> _templateRepository;
public TemplateManager(IRepository<Template> templateRepository)
{
_templateRepository = templateRepository;
}
public ITemplate LoadRoot()
{
return _templateRepository.Retrieve(1); // obviously better logic here.
}
}
class TemplateModule : Module
{
public void Load()
{
Bind<ITemplate>().ToMethod(() => kernel.Get<TemplateManager>().LoadRoot()).InSingletonScope();
}
}
然后我会质疑TemplateManager是否应该成为ninject提供者或内联。
至于实际问题......最大的问题是,如果您决定缓存应该在会话级别而不是应用程序级别由于授权影响,您希望如何以及何时控制清除缓存以强制重新加载模板树?一般来说,我认为应该是对实际类的关注,而不是绑定到你的DI接线或硬连接到类是静态类还是单例(如设计模式,而不是ninject范围)。
我倾向于拥有一个没有静态方法的TemplateManager类,并将其作为容器中的单例类。但是,要获取根模板,消费者应该注入TemplateManager(通过ctor注入),然后说_templateManager.GetRootTemplate()来获取模板。
这样,您可以:
TemplateManager
即,我会像这样管理它:
class TemplateManager
{
readonly IRepository<Template> _templateRepository;
public TemplateManager(IRepository<Template> templateRepository)
{
_templateRepository = templateRepository;
}
ITemplate _cachedRootTemplate;
ITemplate FetchRootTemplate()
{
if(_cachedRootTemplate==null)
_cachedRootTemplate = LoadRootTemplate();
return _cachedRootTemplate;
}
ITemplate LoadRoot()
{
return _templateRepository.Retrieve(1); // obviously better logic here.
}
}
像这样注册:
class TemplateModule : Module
{
public void Load()
{
Bind<TemplateManager>().ToSelf().InSingletonScope();
}
}
然后像这样消费它:
class TemplateConsumer
{
readonly TemplateManager _templateManager;
public TemplateConsumer(TemplateManager templateManager)
{
_templateManager = templateManager;
}
void DoStuff()
{
var rootTempalte = _templateManager.FetchRootTemplate();
狂野的猜测:我也考虑过没有一个单独的IRepository可以在容器中解析(和 可能与工作单位有各种联系)。相反,我让TemplateRepository是一个更长寿的东西,没有耦合到ORM层和工作单元。 IOW有一个存储库和一个Manager,它们都没有做好自己定义的任何事情,这不是一个好兆头 - 存储库不应该只是一个表数据网关 - 它应该能够成为聚合根(如模板)被缓存的地方并整理在一起。但是在没有上下文的情况下抛出类似的东西之前,我必须更多地了解你的代码库!