You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解耦依赖带参数构造函数的类?基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:43:42