如何解耦依赖带参数构造函数的类?基于SOLID与DI的实践
如何解耦带构造参数的依赖类?
这个问题挺典型的——当依赖类需要动态参数时,直接new确实会把两个类死死绑定在一起,完全违背了依赖倒置原则。咱们一步步来拆解怎么解决这个问题:
首先,核心矛盾是类B现在既负责业务逻辑,又负责创建A的实例,这导致B必须知道A的具体构造方式。要解耦,就得把「创建A实例」的责任从B中抽离出去,同时用抽象层隔离B和A的具体实现。
第一步:定义抽象接口
先给A类定义一个抽象接口,这个接口要包含B需要用到的所有成员(如果B需要访问_month,就把它暴露成属性)。这样B只需要依赖这个接口,而不是A的具体类:
// 定义抽象契约,名字可以更贴合业务,比如IMonthEntry public interface IMonthEntry { string Month { get; } }
然后让A类实现这个接口:
public class A : IMonthEntry { private string _month; public string Month => _month; // 实现接口的属性 public A(string month) { _month = month; } }
第二步:用工厂模式转移实例创建责任
因为A需要动态参数month,没法直接把A的实例注入到B里(参数是运行时才确定的),这时候就要用工厂模式——专门用一个类来负责创建A的实例,然后把工厂注入到B中。
1. 定义工厂接口
public interface IMonthEntryFactory { IMonthEntry Create(string month); }
2. 实现工厂类
public class MonthEntryFactory : IMonthEntryFactory { public IMonthEntry Create(string month) { return new A(month); } }
3. 修改B类,注入工厂并使用
现在B不再直接new A(),而是通过工厂创建实例:
public class B { public List<IMonthEntry> ListOfMonths; private readonly IMonthEntryFactory _monthFactory; // 构造函数注入工厂 public B(IMonthEntryFactory monthFactory) { _monthFactory = monthFactory; ListOfMonths = new List<IMonthEntry>(); } public List<IMonthEntry> SomeMethod() { string[] months = new[] { "Jan", "Feb", "Mar" }; foreach (var month in months) { // 通过工厂创建实例,完全和A解耦 var obj = _monthFactory.Create(month); ListOfMonths.Add(obj); } return ListOfMonths; } }
简化方案:用Func替代工厂接口
如果场景比较简单,不想额外定义工厂接口,也可以直接注入Func<string, IMonthEntry>这种委托,它本质上是一个轻量级的工厂:
public class B { public List<IMonthEntry> ListOfMonths; private readonly Func<string, IMonthEntry> _monthCreator; public B(Func<string, IMonthEntry> monthCreator) { _monthCreator = monthCreator; ListOfMonths = new List<IMonthEntry>(); } public List<IMonthEntry> SomeMethod() { string[] months = new[] { "Jan", "Feb", "Mar" }; foreach (var month in months) { var obj = _monthCreator(month); ListOfMonths.Add(obj); } return ListOfMonths; } }
在DI容器中注册这个委托(以.NET为例):
// 直接绑定到A的构造逻辑 services.AddTransient<Func<string, IMonthEntry>>((sp) => (month) => new A(month));
为什么这样解耦有效?
- B现在只依赖抽象(
IMonthEntry和工厂/委托),完全不知道具体实现是A还是其他类,符合依赖倒置原则; - 如果以后要替换A的实现(比如换成
A2,只要它也实现IMonthEntry),只需要修改工厂或委托的注册逻辑,B不需要任何改动; - 实例创建的责任被单独抽离,B可以专注于自己的业务逻辑(处理月份列表),单一职责原则也得到了满足。
内容的提问来源于stack exchange,提问作者cmoe
相关产品推荐
相关产品推荐

