我正在建立一个密码生成器。我正在尝试应用依赖倒置原则(DIP),但到目前为止,我的解决方案似乎仍与具体数据结合在一起。
如何解耦PasswordGenerator?所以我不必通过它
new PasswordRequirementsRepository(new PasswordRequirements{[properties assigned here]})
我可以注入一个接口,该接口将被IoC容器使用?
如何在不创建
PasswordRequirements
实例的情况下将分配给PasswordGenerator
属性的数据传递给PasswordRequirementsRepository
?传递不同的密码要求集时,我很挣扎,因为在PasswordGenerator中,我必须传递PasswordRequirementsRepository的具体实例,而不是接口。我想我要实现的是将PasswordGenerator与具体的密码要求分离。
IPasswordRequirementsRepository.cs
public interface IPasswordRequirementsRepository
{
PasswordRequirements GetPasswordRequirements();
}
PasswordRequirementsRepository.cs
public class PasswordRequirementsRepository : IPasswordRequirementsRepository
{
private readonly PasswordRequirements _requirements;
public PasswordRequirementsRepository(PasswordRequirements requirements)
{
_requirements = requirements;
}
public PasswordRequirements GetPasswordRequirements()
{
return _requirements;
}
}
IPasswordGenerator.cs
public interface IPasswordGenerator
{
string GeneratePassword();
}
PasswordGenerator.cs
public class PasswordGenerator : IPasswordGenerator
{
private readonly IPasswordRequirementsRepository _repository;
public PasswordGenerator(IPasswordRequirementsRepository repository)
{
_repository = repository;
}
public string GeneratePassword()
{
PasswordRequirements requirements = _repository.GetPasswordRequirements();
[password generation logic here]
}
}
PasswordRequirements.cs
public class PasswordRequirements
{
public int MaxLength { get; set; }
public int NoUpper { get; set; }
public int NoLower { get; set; }
public int NoNumeric { get; set; }
public int NoSpecial { get; set; }
}
最佳答案
如何解耦PasswordGenerator?因此,我不必传递给它,而是可以注入一个接口,以供IoC容器使用?
1-派生接口:
public class IPasswordRequirements
{
int MaxLength { get; }
int NoUpper { get; }
int NoLower { get; }
int NoNumeric { get; }
int NoSpecial { get; }
}
2-从接口继承:
public class PasswordRequirements : IPasswordRequirements
{
public int MaxLength { get; set; }
public int NoUpper { get; set; }
public int NoLower { get; set; }
public int NoNumeric { get; set; }
public int NoSpecial { get; set; }
}
3-更新构造函数:
public class PasswordGenerator : IPasswordGenerator
{
public PasswordGenerator(IPasswordRequirements passwordRequirements)
{
}
而已。
不要在这里使用存储库
我担心的是,您对存储库和DI的理解会导致需要一定时间才能始终使用。我认为您缺少的是实例化依赖关系的代码。尽管存储库可能在其核心中提供了它作为其模式的基础,但这并不是正确的选择,原因有两个:首先,您没有将项目存储在存储库中(也就是说,没有分层的虚拟或物理抽象来包装存储库);其次,您没有提供对多种类型的通用访问,只能提供一种类型。
从本质上讲,存储库唯一有用的一件事就是将对象传递给其他层(SQL,文件系统,Web API)的配置/对象。并非在所有情况下都需要存储库才能了解有关如何创建对象的任何信息。
选择适合您需求的框架
相反,您需要的是围绕DI构建的框架。对象创建和处理,并具有用于配置框架的接口/配置,以便它可以了解依赖关系以帮助创建依赖对象。我想到了三个AutoFac,Ninject和Unity。在每种情况下,都需要以某种方式配置每种类型并使用其模式来创建对象。在许多情况下,这些框架甚至可以完全替代其他Microsoft框架(例如,MVC具有自己的实例化对象的方法,但可以用其他DI框架替代)。这些框架绝不需要知道如何将这些对象传递给其他层的配置。它可以简单地通过配置作为副产品来做到这一点,但从根本上讲,它不是所配置的。
例如,使用Autofac,首先要创建构建器,这基本上是创建配置的一种好方法:
var builder = new ContainerBuilder()
然后您注册您的类型:
builder.RegisterType<PasswordRequirements>.As<IPasswordRequirements>();
创建一个用于管理对象的容器:从实例化到配置。
var container = builder.Build();
创建一个定义对象生存期的作用域。
using (var scope = new BeginLifetimeScope())
{
// all objects created by scope which be disposed when the scope is diposed.
var passwordRequirements = scope.Resolve<IPasswordRequirements>();
}
默认情况下,
passwordRequirements
将是new PasswordRequirements()
。从那里您只需建立必要的依赖关系要求,然后让框架处理其余的需求。