【发布时间】:2015-08-25 06:31:12
【问题描述】:
我正在为依赖注入中的单例概念而苦苦挣扎。我不确定类是否应该以支持单例/每个实例实例化的方式实现,以支持打算用作单例的类,或者它们是否应该依赖程序员的正确实例化设置。
如果将在依赖容器中标记为单例,则以下类将按预期工作
...
builder.RegisterType<ApplicationSettings>().AsSelf().SingleInstance();
...
/// <summary>
/// This allows to create many ApplicationSettings instances which each of them will have its collection of settings.
/// Thus we cannot guarantee that one of class has complete settings
/// </summary>
public class ApplicationSettings
{
private readonly object _locker = new object();
private readonly Dictionary<string, object> _settings;
private readonly ILog _log;
public ApplicationSettings(ILog log)
{
_log = log;
_settings = LoadSettings();
Thread.Sleep(3000); //inner hardwork, e.g. cashing of something
}
public object GetSettings(string key)
{
lock (_locker)
{
return _settings.ContainsKey(key) ? _settings[key] : null;
}
}
public void SetSettings(string key, object value)
{
lock (_locker)
{
_settings.Remove(key);
_settings.Add(key, value);
}
}
public void Remove(string key)
{
lock (_locker)
{
_settings.Remove(key);
}
}
public void Save()
{
Thread.Sleep(5000); //Saving somewhere
}
private Dictionary<string, object> LoadSettings()
{
Thread.Sleep(5000); //Long loading from somewhere
return new Dictionary<string, object>();
}
}
需要使用 ApplicationSettings 类的所有类都将共享一个实例,因此 Settings 将在保存到某个位置时包含所有信息。另一方面,如果程序员没有将类标记为 SingleInstance,则保存时会出现问题,因为如果将其实现为替换存储位置中的整个集合,则不会保存所有设置。因此,正确的功能很大程度上取决于程序员对类的了解并将其用作单例。
在第二个示例中,我将静态字段用于设置,这允许我将类用作单例或作为每个实例的实例而不影响核心功能(我的意思是,如果将使用更多 ApplicationSettings2 实例,则不会保存所有设置)
/// <summary>
/// This allows to create many ApplicationSettings2 instances which each of them will share same collection of settings.
/// </summary>
public class ApplicationSettings2
{
private static readonly object Locker = new object();
private static readonly Dictionary<string, object> Settings;
private readonly ILog _log;
static ApplicationSettings2()
{
Settings = LoadSettings();
Thread.Sleep(3000); //inner hardwork, e.g. cashing of something
}
public ApplicationSettings2(ILog log)
{
_log = log;
}
public object GetSettings(string key)
{
lock (Locker)
{
return Settings.ContainsKey(key) ? Settings[key] : null;
}
}
public void SetSettings(string key, object value)
{
lock (Locker)
{
Settings.Remove(key);
Settings.Add(key, value);
}
}
public void Remove(string key)
{
lock (Locker)
{
Settings.Remove(key);
}
}
public void Save()
{
Thread.Sleep(5000); //Saving somewhere
}
private static Dictionary<string, object> LoadSettings()
{
Thread.Sleep(5000);
return new Dictionary<string, object>();
}
}
类使用的两种方法
...
builder.RegisterType<ApplicationSettings>().AsSelf().SingleInstance();
...
或
...
builder.RegisterType<ApplicationSettings>().AsSelf();
...
将导致相同的预期功能。唯一的区别是,不是单例实例化模式会导致功能变慢(ctor 中有一个睡眠),但最终改变实例化模式不会破坏任何东西。
我的问题:
- 谁负责定义在依赖容器配置中应将哪个类用作单例?
- 这些关于实例化的信息应该存储在哪里?
- 我是否应该实现打算用作单例的类,以便即使在每个实例都实例化的环境中也能工作?
- 如果我将第 3 方 DLL 的类添加到我的依赖容器配置中,谁负责告诉我应该如何实例化这个类? (程序员如何知道他应该使用哪种实例?这些信息应该是文档的强制性部分,还是程序员应该只使用“尝试/使用”方法?)
- 是否应该将“单例”仅用作如何使系统更快的方式,但应该是单例以便即使它们被多次实例化也能够工作? (依赖容器配置中缺少 SingleInstance 关键字)
【问题讨论】:
标签: .net design-patterns dependency-injection