给出以下代码:
public interface ISomeClient;
public class SomeClient : ISomeClient
{
SomeClient(string clientID, string clientSecret) {
_clientID = clientID;
_clientSecret = clientSecret;
}
}
public class SomeWrapper {
SomeWrapper(ISomeClient someClient) {
_someClient = someClient;
}
}
此代码应该允许依赖项注入,但我不喜欢依赖项“某些客户端”需要参数。这似乎不是一个干净的方法。在让用户轻松使用“SomeWrapper”的同时进行这种类型的分离的正确方法是什么?
我考虑过的解决方案是:
所提供的代码的主要问题是 SomeClient 类需要构造函数参数,这可能会使其在 SomeWrapper 类中使用起来不太方便。这可能会导致潜在的耦合和应用程序设计灵活性的降低。
有效的依赖注入解决方案:
要解决此问题并实现干净的依赖项注入,请考虑以下方法:
重构 SomeClient:修改 SomeClient 类以在其构造函数中接受可选参数。这允许您提供默认值或使用依赖项注入来提供参数。
public class SomeClient : ISomeClient
{
public SomeClient(string clientID = null, string clientSecret = null)
{
_clientID = clientID ?? "defaultClientID";
_clientSecret = clientSecret ?? "defaultClientSecret";
}
}
优点: 保持清晰的关注点分离。 提供如何提供参数的灵活性。 可以与其他依赖注入技术结合使用。
注意事项: 确保默认值适合您的用例。 考虑使用依赖注入框架来自动管理参数注入。
利用框架:使用依赖注入框架,如 Microsoft 内置的 IServiceProvider 或第三方库,如 Autofac 或 SimpleInjector。 配置服务:向依赖项注入容器注册 SomeClient 和 SomeWrapper,并提供必要的参数。 使用 Microsoft 的 IServiceProvider 的示例:
public class SomeWrapper
{
public SomeWrapper(ISomeClient someClient)
{
_someClient = someClient;
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ISomeClient, SomeClient>();
services.AddTransient<SomeWrapper>();
}
}
优点: 简化依赖关系管理并减少样板代码。 提供生命周期管理和依赖关系解析等功能。 与 .NET 生态系统的其他部分很好地集成。
注意事项: 需要额外的设置和配置。 可能会为新团队成员引入学习曲线。
创建工厂类:实现一个工厂类,负责创建具有所需参数的 SomeClient 实例。
public class SomeClientFactory
{
public ISomeClient CreateClient(string clientID, string clientSecret)
{
return new SomeClient(clientID, clientSecret);
}
}
优点: 提供用于创建实例的集中点。 可以封装复杂的实例化逻辑。 提供选择创建方法的灵活性。
注意事项: 如果广泛使用,可能会带来额外的复杂性。 需要仔细管理工厂实例。
提取参数传递:创建一个单独的方法来处理向 SomeClient 传递参数。
public class SomeWrapper
{
public SomeWrapper(string clientID, string clientSecret)
{
_someClient = CreateSomeClient(clientID, clientSecret);
}
private ISomeClient CreateSomeClient(string clientID, string clientSecret)
{
return new SomeClient(clientID, clientSecret);
}
}
优点: 可以提高代码的组织性和可读性。 为参数传递提供一定程度的抽象。
注意事项: 如果广泛使用,可能会带来额外的复杂性。 可能不如其他方法那么灵活。
选择正确的方法:
最佳方法取决于您的具体项目要求和偏好。考虑以下因素:
参数传递的复杂性:如果参数传递相对简单,带有可选参数的构造函数注入可能就足够了。 与其他框架集成:如果您使用依赖项注入框架,那么利用其功能可能会有所帮助。 代码组织和可维护性:评估每种方法如何影响代码的整体结构和可读性。 通过仔细考虑这些因素并应用适当的技术,您可以有效地将依赖项注入合并到 C# 代码中,从而促进更好的模块化、可测试性和可维护性。