Architecture problem: use of dependency injection resulting in rubbish API

送分小仙女□ 提交于 2019-12-05 11:15:55

As Morten points out, move the non injectable dependecies from the constructor call to the method(s) that actually need to use it,

If you have constructor paramters that can't (or are difficult to) be injected you won't be able to autmatically inject IAssetRegister into any class that needs it either.

You could always, of course, create a IUserProvider interface with a concrete implementation along these lines:

public class UserProvider : IUserProvider 
{
    // interface method
    public User GetUser() 
    {
        // you obviously don't want a page dependency here but ok...
        return GetUserFromPage();
    }
}

Thus creating another injectable dependency where there was none. Now you eliminate the need to pass a user to every method that might need it.

Try separating the message from the behavior. Make a class that holds the data for the operation, and create a different class that contains the business logic for that operation. For instance, create this command:

public class RegisterAssetCommand
{
    [Required]
    public int CaseNumber { get; set; }

    [Required]
    public User Operator { get; set; }
}

Now define an interface for handling business commands:

public interface ICommandHandler<TCommand>
{
    void Handle(TCommand command);
}

Your presentation code will now look like this:

var command = new RegisterAssetCommand
{
    CaseNumber = 1000,
    Operator = GetUserFromPage(),
};

var commandHandler = WindsorContainer
    .Resolve<ICommandHandler<RegisterAssetCommand>);

commandHandler.Handle(command);

Note: If possible, move the responsibility of getting a commandHandler out of the presentation class and inject it into the constructor of that class (constructor injection again).

No you can create an implementation of the ICommandHandler<RegisterAssetCommand> like this:

public class RegisterAssetCommandHandler
    : ICommandHandler<RegisterAssetCommand>
{
    private ILawbaseAssetRepository lawbaseAssetRepository;
    private IAssetChecklistKctcPartRepository assetRepository;

    public RegisterAssetCommandHandler(
        ILawbaseAssetRepository lawbaseAssetRepository,
        IAssetChecklistKctcPartRepository assetRepository)
    {
        this.lawbaseAssetRepository = lawbaseAssetRepository;
        this.assetRepository = assetRepository;
    }

    public void Handle(RegisterAssetCommand command)
    {
        // Optionally validate the command

        // Execute the command
    }
}

Optionally, you could perhaps even leave the User out of the RegisterAssetCommand by injecting a IUserProvider in the RegisterAssetCommandHandler. The IUserProvider interface could have an GetUserForCurrentContext that the handler can call.

I hope this makes sense.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!