嵌套动态对象创建场景下的依赖注入优化方案咨询
看起来你正被深层嵌套对象的依赖传递问题困扰——直接用静态类确实能快速“解决”问题,但长期来看会带来耦合度高、单元测试困难(比如没法轻松替换依赖)、线程安全隐患等一堆麻烦。我给你几个更优雅的方案,你可以根据自己的场景选择:
方案一:依赖注入容器 + 工厂模式(首推)
这个方案最符合依赖注入的设计原则,能清晰管理依赖关系,同时让A类不用关心具体Condition的依赖细节。
步骤1:定义条件工厂
先创建一个工厂类,专门负责创建各种Condition实例,工厂本身通过构造注入拿到所需的依赖:
public interface IConditionFactory { Condition CreatePriceIsHigherCondition(double price); // 可以根据需求添加其他条件的创建方法 } public class ConditionFactory : IConditionFactory { private readonly IPriceList _priceList; // 构造注入IPriceList,由DI容器负责传入 public ConditionFactory(IPriceList priceList) { _priceList = priceList; } public Condition CreatePriceIsHigherCondition(double price) { return new PriceIsHigherCondition(price, _priceList); } }
步骤2:修改A类依赖工厂
让A类依赖工厂接口,而不是直接创建Condition:
public class A { private List<Condition> _conditions = new List<Condition>(); private readonly IConditionFactory _conditionFactory; public A(IConditionFactory conditionFactory) { _conditionFactory = conditionFactory; } public void CreateConditionsFromJson() { // 现在创建条件只需要调用工厂,不用管依赖传递了 _conditions.Add(_conditionFactory.CreatePriceIsHigherCondition(3.4)); } }
步骤3:注册依赖到DI容器
在程序入口(比如Main)把所有依赖注册到DI容器(比如微软自带的Microsoft.Extensions.DependencyInjection,或者Autofac等第三方容器):
static void Main(string[] args) { var services = new ServiceCollection(); // 注册IPriceList的实现 services.AddSingleton<IPriceList, PriceList>(); // 注册工厂 services.AddSingleton<IConditionFactory, ConditionFactory>(); // 注册A类(如果A是被其他类依赖,也可以在这里注册) services.AddSingleton<A>(); var serviceProvider = services.BuildServiceProvider(); // 从容器获取A实例,所有依赖会自动注入 var a = serviceProvider.GetRequiredService<A>(); }
这个方案的优势是依赖关系清晰,单元测试时可以轻松替换工厂或IPriceList的实现,代码可维护性拉满。
方案二:服务定位器模式(谨慎使用)
这个模式相当于一个全局的DI入口,比静态类灵活,但会隐藏依赖关系,适合老项目改造或者实在没办法的场景。
步骤1:实现服务定位器
public static class ServiceLocator { private static IServiceProvider _serviceProvider; // 在程序初始化时传入DI容器 public static void Initialize(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } // 获取指定类型的服务 public static T GetService<T>() where T : notnull { return _serviceProvider.GetRequiredService<T>(); } }
步骤2:初始化并使用
在Main里初始化定位器,然后修改PriceIsHigherCondition的构造:
static void Main(string[] args) { var services = new ServiceCollection(); services.AddSingleton<IPriceList, PriceList>(); var serviceProvider = services.BuildServiceProvider(); ServiceLocator.Initialize(serviceProvider); } public class PriceIsHigherCondition : Condition { double _price; IPriceList _priceList; public PriceIsHigherCondition(double price) { _price = price; // 从服务定位器获取依赖 _priceList = ServiceLocator.GetService<IPriceList>(); } public override bool IsTrue() { return _price > _priceList.GetPrice(); } }
这样A类里创建条件时就不用传依赖了,但要注意:这个模式会让代码的依赖关系变得不直观,单元测试时需要先初始化定位器,所以除非万不得已,优先选方案一。
方案三:将依赖放到执行上下文
如果你的Condition创建和执行是分离的,可以把依赖放到执行上下文里,只在需要判断的时候传入:
步骤1:定义执行上下文
public abstract class Condition { // 修改IsTrue方法,接收上下文参数 public abstract bool IsTrue(IExecutionContext context); } public interface IExecutionContext { IPriceList PriceList { get; } } public class ExecutionContext : IExecutionContext { public IPriceList PriceList { get; } public ExecutionContext(IPriceList priceList) { PriceList = priceList; } }
步骤2:修改条件类
public class PriceIsHigherCondition : Condition { double _price; public PriceIsHigherCondition(double price) { _price = price; } public override bool IsTrue(IExecutionContext context) { return _price > context.PriceList.GetPrice(); } }
这样创建Condition时不用传依赖,只有在执行判断的时候才传入上下文。这个方案适合条件创建后不会立即执行,而是在后续某个时机触发的场景。
总的来说,方案一(DI容器+工厂)是最优选择,它既解决了依赖传递的问题,又保持了代码的可维护性和可测试性。静态类虽然简单,但后续维护和测试会踩很多坑,尽量避免。
备注:内容来源于stack exchange,提问作者OlavT

