我正在编写以下课程
public class UserApplication
{
private IUserRepository UserRepository { get; set; }
private IUserEmailerService UserEmailerService { get; set; }
public UserApplication(IUserRepository userRepository, IUserEmailerService userEmailerService)
{
this.UserRepository = userRepository;
this.UserEmailerService = userEmailerService;
}
public bool Authenticate(string login, string pass)
{
// Here I use UserRepository Dependency
}
public bool ResetPassword(string login, string email)
{
// Here I only use both Dependecies
}
public string GetRemeberText(string login, string email)
{
// Here I only use UserRepository Dependency
}
}
我正在使用Unity来管理我的实例,所以我意识到我只在一个方法上使用这两个依赖项,所以当我要求容器为这个类提供一个实例时,两个依赖项都注入到这个类中但是我没有需要所有方法的两个实例,因此在Authenticate用户中我只需要存储库。 我这样做错了吗?还有另一种方法,只有我在本课程中用于所有案例的依赖吗?
我想使用命令模式,所以我用一个方法来分类3个类,只有我需要的依赖项,如下所示:
public class AuthenticateUserCommand : ICommand
{
private IUserRepository UserRepository { get; set; }
public string Login { get; set; }
public string Password { get; set; }
public void Execute()
{
// executes the steps to do that
}
}
public class ResetUserPasswordCommand : ICommand
{
private IUserRepository UserRepository { get; set; }
private IUserEmailerService UserEmailerService { get; set; }
public string Login { get; set; }
public string Email { get; set; }
public void Execute()
{
// executes the steps to do that
}
}
答案 0 :(得分:0)
另一种方法是为每个行为创建特定于角色的界面。因此,您有IUserAuthenticationService
,IUserPasswordResetService
和IUserRememberPasswordService
。接口可以由单个类实现,例如UserApplication
,也可以使用单个类来实现,以维护SRP。您描述的命令模式对SRP具有类似的优势。命令模式的一个问题是这些依赖关系仍然必须由某些东西提供。如果依赖项是由控制器提供的,那么您仍然必须首先将依赖项提供给控制器,并且您将遇到与第一个示例类似的问题。
角色特定界面案例以及命令模式的权衡是内聚力的丧失。这样做的成本肯定是偏好和视角的问题,以及您希望强制执行SRP的程度。一方面,通过使用单个类处理认证相关行为而提供的内聚可能是有益的。另一方面,它可能导致依赖性错位,如您所述。
答案 1 :(得分:0)
我通常会在你考虑的时候实现一种命令模式。但是,它也有eulerfx提到的元素。我只是称他们为任务。例如:
public interface ITask
{
void Execute();
}
public interface IAuthenticateTask : ITask {}
public interface IResetPasswordTask : ITask {}
然后我实现了这些并注入了所需的依赖项。所以我有角色特定的接口和实现。
我会不按照您在答案位中的说明使用服务定位器。
当我确实需要像在ASP.NET MVC项目的控制器中那样访问各种任务时,我使用属性注入而不是构造函数注入。我只是让我的DI容器(我使用城堡)需要在运行时基于约定进行某些注射。
通过这种方式,我仍然可以轻松地测试控制器,因为我不需要提供所有构造函数注入的对象,而只需要提供测试所需的那些属性,还有一些额外的好处,即仍然需要某些注入的属性。将由构造函数注入提供。
<强>更新强>
使用这种方法有几种选择。人们对任务感兴趣的主要界面是角色特定的。诸如ITask
之类的继承接口仅仅是为了方便起见。它也可以用泛型扩展:
public interface ITask<TInput>
{
void Execute(TInput input);
}
public interface IOutputTask<TOutput>
{
TOutput Execute();
}
public interface IOutputTask<TOutput, TInput>
{
TOutput Execute(TInput input);
}
这些都是为了方便起见:
public interface IAuthenticateTask : IOutputTask<bool> {}
// or
public interface IAuthenticateTask : IOutputTask<AuthenticationResult> {}
您可以在角色级别上工作:
public interface IAuthenticateTask
{
AuthenticationResult Execute(string username, string password);
}
只需依赖特定于角色的依赖关系接口。
答案 2 :(得分:0)
我这样做错了吗?
没有。 2个依赖项不是世界末日,它们不会使构造函数变得臃肿或不可读。
以前给出的答案很适合你有3-4 +依赖的情况。
如果仅在该方法中使用,您还可以偶尔将特定依赖项作为参数传递给方法。从这个意义上说,你可能想给Unity method call injection一个尝试,虽然我不确定它是否真正用于此目的。