1

我正在写以下课程

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 来管理我的实例,所以我意识到我只在一个方法上使用两个依赖项,所以当我要求容器为这个类提供一个实例时,两个依赖项都注入到这个类中,但我不需要这两个所有方法的实例,因此在验证用户中我只需要存储库。那我这样做错了吗?是否有另一种方法仅具有我在此类中的所有情况下使用的依赖关系?

我想使用命令模式,所以我用一种方法对 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
    }
}
4

3 回答 3

0

I usually implement a form of the command pattern as you are considering doing. However, it also has elements of what eulerfx has mentioned. I just call them tasks. For example:

public interface ITask
{
    void Execute();
}

public interface IAuthenticateTask : ITask {}

public interface IResetPasswordTask : ITask {}

I then implement these and have the required dependencies injected. So I have role specific interfaces and implementations.

I would not go with the service locator as you stated in your answer bit.

When I do have a situation where I need access to various tasks as I do in the controller of an ASP.NET MVC project I use property injection instead of constructor injection. I just have my DI container (I use castle) require certain injections based on a convention at runtime.

In this way I can still easily test the controller since I do not need to provide all the constructor injected objects but only those properties that I need for the test, with the added benefit that certain injected properties will still be required just as would be provided by constructor injection.

update:

There are a couple of options available using this approach. The main interface one would be interested in for a task is the role-specific one. The inherited interface(s) such as ITask would be only for convenience in simple cases. It can be extended also with generics:

public interface ITask<TInput>
{
   void Execute(TInput input);
}

public interface IOutputTask<TOutput>
{
   TOutput Execute();
}

public interface IOutputTask<TOutput, TInput>
{
   TOutput Execute(TInput input);
}

Once again these are for convenience:

public interface IAuthenticateTask : IOutputTask<bool> {}

// or

public interface IAuthenticateTask : IOutputTask<AuthenticationResult> {}

You could work just on the role level:

public interface IAuthenticateTask
{
    AuthenticationResult Execute(string username, string password);
}

One need only rely on the role-specific interface for dependencies.

于 2013-03-13T04:40:35.400 回答
0

另一种方法是为每个行为创建一个角色特定的界面。所以你会有IUserAuthenticationService,IUserPasswordResetServiceIUserRememberPasswordService. 接口可以由单个类实现,例如,UserApplication或者它们可以用单独的类实现以维护 SRP。您描述的命令模式对 SRP 具有类似的优势。命令模式的一个问题是这些依赖项仍然必须由某些东西提供。如果依赖项是由控制器提供的,那么您仍然必须首先将依赖项获取到控制器,并且您会遇到与第一个示例类似的问题。

角色特定的接口案例和命令模式的权衡是失去凝聚力。这样做的成本当然是一个偏好和观点的问题,就像您想要执行 SRP 的程度一样。一方面,由单个类处理身份验证相关行为所提供的凝聚力可能是有益的。另一方面,正如您所描述的,它可能会导致依赖关系错位。

于 2013-03-13T02:38:01.877 回答
0

那我这样做错了吗?

第 2 个依赖项并不是世界末日,它们不会使构造函数变得臃肿或不可读。

之前给出的答案非常适合您有 3-4 个以上依赖项的情况。

如果仅在该方法中使用,您也可以偶尔将特定依赖项作为参数传递给该方法。从这个意义上说,您可能想尝试一下 Unity 的方法调用注入,尽管我不确定它是否正是为此目的。

于 2013-03-13T17:00:39.713 回答