C# 架构问题:使用依赖注入导致垃圾API
我正在尝试创建一个类,它可以执行各种与数据库相关的低级操作,但向UI层提供一个非常简单的接口 这个类表示一组数据,所有数据都在一个特定的聚合根中,由一个ID int检索 构造函数采用四个参数:C# 架构问题:使用依赖注入导致垃圾API,c#,api,architecture,dependency-injection,castle-windsor,C#,Api,Architecture,Dependency Injection,Castle Windsor,我正在尝试创建一个类,它可以执行各种与数据库相关的低级操作,但向UI层提供一个非常简单的接口 这个类表示一组数据,所有数据都在一个特定的聚合根中,由一个ID int检索 构造函数采用四个参数: public AssetRegister(int caseNumber, ILawbaseAssetRepository lawbaseAssetRepository, IAssetChecklistKctcPartRepository assetChecklistKctcPartRepository,
public AssetRegister(int caseNumber, ILawbaseAssetRepository lawbaseAssetRepository, IAssetChecklistKctcPartRepository assetChecklistKctcPartRepository, User user)
{
_caseNumber = caseNumber;
_lawbaseAssetRepository = lawbaseAssetRepository;
_assetChecklistKctcPartRepository = assetChecklistKctcPartRepository;
_user = user;
LoadChecklists();
}
UI层通过接口IAssetRegister
访问此类。Castle Windsor可以提供ILawbaseAssetRepository和IAssetChecklistKctcPartRepository参数本身,但UI代码需要使用以下匿名类型提供其他两个参数:
int caseNumber = 1000;
User user = GetUserFromPage();
IAssetRegister assetRegister = Moose.Application.WindsorContainer.Resolve<IAssetRegister>(new { caseNumber, user});
var command = new RegisterAssetCommand
{
CaseNumber = 1000,
Operator = GetUserFromPage(),
};
var commandHandler = WindsorContainer
.Resolve<ICommandHandler<RegisterAssetCommand>);
commandHandler.Handle(command);
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
}
}
int caseNumber=1000;
User=GetUserFromPage();
IAssetRegister assetRegister=Moose.Application.WindsorContainer.Resolve(新{caseNumber,user});
从API设计的角度来看,这是垃圾。UI层开发人员无法知道IAssetRegister需要一个整数和一个用户。他们需要了解类的实现才能使用它
我知道我这里一定有设计问题。有人能给我一些建议吗?正如Morten指出的,将不可注入依赖项从构造函数调用移动到实际需要使用它的方法 如果您有无法(或很难)注入的构造函数参数,那么您也无法自动将
IAssetRegister
注入到任何需要它的类中
当然,您始终可以创建一个带有以下具体实现的IUserProvider
接口:
public class UserProvider : IUserProvider
{
// interface method
public User GetUser()
{
// you obviously don't want a page dependency here but ok...
return GetUserFromPage();
}
}
从而创建了另一个不存在的可注入依赖项。现在,您不再需要将用户传递给可能需要它的每个方法。尝试将消息与行为分开。创建一个保存操作数据的类,并创建一个包含该操作的业务逻辑的不同类。例如,创建以下命令:
public class RegisterAssetCommand
{
[Required]
public int CaseNumber { get; set; }
[Required]
public User Operator { get; set; }
}
现在定义一个用于处理业务命令的接口:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
或者,您甚至可以通过在RegisterAssetCommandHandler
中注入IUserProvider
将User
从RegisterAssetCommandHandler
中退出。IUserProvider
接口可以有一个处理程序可以调用的GetUserForCurrentContext
我希望这是有意义的。仅对可注入依赖项使用构造函数注入。将手动指定的值移动为方法参数,或在construction.lol@TheppDeveloper's edit之后提供一种方法来设置它们!是的,那个编辑也让我笑了。不确定你们是否真的应该这样“搞乱作者的风格个性:)不是DI导致了垃圾API。你用的是SL,这是常见的气味。不要做SL。我从来没有说DI本身会导致一个垃圾API,只是我(错误地)使用了它。对不起,我不理解这段代码。我需要更多的汤匙。如何获取IAssetRegister实例?您的
IAssetRegister
已不存在。它被分为两类:一类是RegisterAssetCommand
,另一类是ICommandHandler
。您在IAssetRegister
实现中放入的代码应该放入RegisterAssetCommandHandler
类的Handle
方法中。哦,我想我明白了。您认为IAssetRegister只是执行一些命令。事实上,它基本上就像一个实体——它包含状态。话虽如此,我认为问题在于设计——我需要一个存储库来为我提供资产注册。然后我可以将案例编号和用户提供给存储库的加载方法。让你的实体依赖于服务通常是个坏主意,但我想你已经明白了,因为这就是你的问题所在。顺便说一句,你的博客看起来棒极了。喝了一杯浓烈的咖啡后,我会试试看的!:)这个用户提供者的想法可以为我解决几个问题。谢谢。好的,我解决了这个问题。我使用IUserProvider类型接口获取当前用户(当然是注入的),并通过方法调用而不是构造函数提供案例编号。现在,我的API不需要开发人员进行任何猜测。谢谢大家!!哦,IUserProvider的概念也为我解决了这个问题:这超出了我的期望;)