我有一个User
实体,它有一个HasCompletedSecurity
属性,指示该特定User
是否回答了系统所需的安全问题数量。系统所需的安全问题数量是可配置的,可以从配置文件中检索。User
类应如何访问配置的信息?
我目前有一个IConfigurationService
接口,其后有使用 ConfigurationManager
或 Azure 等效项(如果可用(的实现。我已经通过静态 InjectionService
类封装了对 DI 容器的访问,并且目前正在解析配置的值,如下所示:
public class User
{
private static readonly IConfigurationService _configurationService =
InjectionService.Resolve<IConfigurationService>();
public bool HasCompletedSecurity
{
get
{
// Uses the static _configurationService to get the
// configured value:
int numberOfRequiredResponses =
GetConfiguredNumberOfRequiredResponses();
return this.SecurityQuestionResponses.Count()
>=
GetConfiguredNumberOfRequiredResponses();
}
}
}
这当然是ServiceLocator反模式的一个例子,我一点也不喜欢它。静态依赖关系使得使用此类的任何内容都变得笨拙。
我正在使用实体框架并从这里得到提示,我不想通过 DI 容器传递我的实体来为它们提供依赖项,所以......我应该如何访问配置的值?
编辑:一方面是这个确切的例子(我非常感谢关于它的正确架构的建议(,我感兴趣的更大问题是你如何管理对来自实体的服务的非静态引用?答案是否只是以您永远不需要的方式构建实体?
以下是我定义 User 类的方法:
public class User
{
public bool HasCompletedSecurity { get; set; }
// other members...
}
说真的,这是一个更好的解决方案,因为它沿时间维度分离了值。考虑一下:如果用户在 2010 年完成了所有安全问题,而您后来更改了业务规则,那么您是否要使现有用户无效?
在大多数情况下,记录并坚持用户在过去某个时候完成了当时有效的安全过程可能更合理。这样,您就不会打扰现有用户。
您仍然可以使用控制反转的概念,而无需使用任何类型的 IoC 容器或要求在实体的构造函数中使用它。我会使用准策略模式来解决这个问题,并有这样的东西:
public interface ISecurityPolicy
{
public int MinimumSecurityQuestionResponses { get; }
}
public class User
{
public void HasCompletedSecurity (ISecurityPolicy security_policy)
{
return this.SecurityQuestionResponses.Count()
>= security_policy.MinimumSecurityQuestionResponses;
}
}
这就将提供用户必须满足的特定安全策略的责任放在调用方身上,而不是 User 类本身。
从那时起,您可以根据需要提供该额外参数,也许将其包装在将ISecurityPolicy
注入服务等的IUserSecurityService
中。
这仍然是控制反转,但它是在方法级别,因为这个特定方法实际上是唯一关心安全策略/配置的方法。