3 回答
TA贡献1830条经验 获得超3个赞
依赖注入作为一种实践,旨在引入抽象(或接缝)以解耦易变的依赖关系。易失性依赖是一个类或模块,除其他外,它可以包含不确定的行为,或者通常是您可以替换或拦截的东西。
有关 volatile 依赖项的更详细讨论,请参阅我的书的这本可自由阅读的介绍的第 1.3.2 节。
因为您FileLogger
写入磁盘,它包含非确定性行为。出于这个原因,您介绍了ILoggable
抽象。这允许消费者与实现分离FileLogger
。
但是,为了能够成功地将消费者与其可变依赖项解耦,您需要将该依赖项注入消费者。共有三种常见模式可供选择:
构造函数注入——依赖被静态定义为类实例构造函数的参数列表。
属性注入——依赖通过可写的实例属性注入消费者。
方法注入——依赖项作为方法参数注入消费者。
构造函数注入和属性注入都应用在应用程序的启动路径(也称为Composition Root)中,并要求使用者将依赖项存储在私有字段中以供以后重用。这要求构造函数和属性是实例成员,即非静态的。静态构造函数不能有任何参数,静态属性会导致Ambient Context 反模式(参见第 5.3 节)和Temporal Coupling。这阻碍了可测试性和可维护性。
另一方面,方法注入是在组合根之外应用的,它不存储任何提供的依赖项,而只是使用它。
因此,方法注入是三种模式中唯一可以同时应用于实例方法和静态方法的模式。
在这种情况下,方法的使用者必须提供依赖。然而,这确实意味着消费者本身必须通过构造函数、属性或方法注入提供该依赖项。
您在其构造函数LogService
中创建的静态示例是紧密耦合代码的一个很好的示例。FileLogger
这被称为Control Freak 反模式(第 5.1 节),或者通常可以视为DIP 违规。这与 DI正好相反。
为了防止 volatile 依赖项的紧密耦合,最好的方法是制作LogService
非静态并将其 volatile 依赖项注入其唯一的公共构造函数中。
TA贡献1900条经验 获得超5个赞
将依赖注入 (DI) 与静态类一起使用是没有意义的。而不是 DI,只需向静态类添加一个初始化方法并传入依赖项。
public static class LogService
{
private static ILoggable _logger;
public static ILoggable Logger
{
get
{
return _logger;
}
}
public static void InitLogger(ILoggable logger)
{
_logger = logger;
}
}
要使用记录器,只需确保先调用InitLogger():
LogService.InitLogger(new FileLogger());
LogService.Logger.WriteLine("message");
TA贡献1789条经验 获得超10个赞
您可以对需要注入静态类的任何对象使用延迟初始化。
https://docs.microsoft.com/en-us/dotnet/api/system.lazy-1?view=net-5.0
这将允许您传递可以在正在运行的实例和需要使用这些对象的其他类/方法之间共享的静态对象。一个示例是您希望在整个应用程序中共享的 HttpClient。您可以在静态类中延迟初始化 HttpClient 并引用静态类来获取 HttpClient。
这是使用 CosmosDB 客户端的另一个示例: https ://docs.microsoft.com/en-us/azure/azure-functions/manage-connections?tabs=csharp#azure-cosmos-db-clients
- 3 回答
- 0 关注
- 683 浏览
添加回答
举报