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

如何用抽象工厂处理构造参数不同的接口实现及服务注入问题?

问题描述

当接口实现类的构造函数一致时,所有功能运行正常,但当构造函数存在差异时,遇到了难题。这种实现方式是否可行,还是存在架构层面的问题?

相关代码如下:

public class CategoryViewFactory : ICategoryViewFactory
{
    private readonly ActiveProgressions _activeProgressions;

    public CategoryViewFactory(ActiveProgressions activeProgressions)
    {
        _activeProgressions = activeProgressions;
    }

    public ICategoryView? Create(CategoryType type, Category category)
    {
        return type switch
        {
            CategoryType.Category => new CategoryView(category),
            CategoryType.Subcategory => new SubcategoryView(category, _activeProgressions),
            _ => null
        };
    }
}

补充疑问:

  • ActiveProgressions是通过容器注入的单例服务,这种实现是否合理?
  • 若ActiveProgressions为瞬态服务,该如何创建SubcategoryView?认为在Create()方法中添加额外参数的方案并不理想,但似乎是当前唯一的解决办法。

解答

一、单例ActiveProgressions时的实现合理性

当前实现是合理的,核心原因如下:

  • 单例服务的设计目标就是被多个消费者共享,工厂类通过构造函数注入持有单例ActiveProgressions的引用,不存在生命周期冲突问题。
  • 遵循依赖注入原则,工厂类的依赖由外部注入而非内部硬编码,保证了可测试性——你可以轻松替换ActiveProgressions的模拟实现来验证工厂逻辑。
  • 潜在的小局限:如果后续CategoryView也需要依赖其他服务,直接new的写法会让工厂类职责逐渐膨胀,但当前场景下是完全可控的。

二、瞬态ActiveProgressions时的解决方案

如果ActiveProgressions是瞬态服务(每次请求需要新实例),构造函数注入的方式会出现问题:若工厂类是单例,会一直持有同一个瞬态实例,违背其设计意图;若工厂类也是瞬态,虽能解决但并非最优解。以下是几种比给Create()加参数更优的方案:

1. 拆分独立视图创建者(推荐)

遵循单一职责原则,将不同视图的创建逻辑拆分到单独类中,主工厂仅负责分发请求:

// 定义视图创建者通用接口
public interface ICategoryViewCreator
{
    CategoryType TargetType { get; }
    ICategoryView Create(Category category);
}

// CategoryView专属创建者
public class CategoryViewCreator : ICategoryViewCreator
{
    public CategoryType TargetType => CategoryType.Category;

    public ICategoryView Create(Category category)
    {
        return new CategoryView(category);
    }
}

// SubcategoryView专属创建者,自动注入瞬态ActiveProgressions
public class SubcategoryViewCreator : ICategoryViewCreator
{
    private readonly ActiveProgressions _activeProgressions;

    public SubcategoryViewCreator(ActiveProgressions activeProgressions)
    {
        _activeProgressions = activeProgressions;
    }

    public CategoryType TargetType => CategoryType.Subcategory;

    public ICategoryView Create(Category category)
    {
        return new SubcategoryView(category, _activeProgressions);
    }
}

// 重构后的主工厂
public class CategoryViewFactory : ICategoryViewFactory
{
    private readonly IEnumerable<ICategoryViewCreator> _creators;

    public CategoryViewFactory(IEnumerable<ICategoryViewCreator> creators)
    {
        _creators = creators;
    }

    public ICategoryView? Create(CategoryType type, Category category)
    {
        var creator = _creators.FirstOrDefault(c => c.TargetType == type);
        return creator?.Create(category);
    }
}

该方案优势:

  • 每个创建者只负责一种视图的创建,职责清晰,后续新增视图只需添加新创建者类,无需修改主工厂(符合开闭原则)。
  • 依赖关系完全由DI容器管理,瞬态服务的生命周期自动匹配,不会出现资源泄漏或实例复用错误。

2. 使用服务定位器(简易场景备选)

直接从DI容器中解析瞬态ActiveProgressions实例,适合快速解决简单场景,但需注意避免过度使用(会降低代码的可测试性和透明性):

public class CategoryViewFactory : ICategoryViewFactory
{
    private readonly IServiceProvider _serviceProvider;

    public CategoryViewFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public ICategoryView? Create(CategoryType type, Category category)
    {
        return type switch
        {
            CategoryType.Category => new CategoryView(category),
            CategoryType.Subcategory => new SubcategoryView(
                category, 
                _serviceProvider.GetRequiredService<ActiveProgressions>()),
            _ => null
        };
    }
}

3. 让视图类由DI容器管理(依赖较多场景适用)

如果ICategoryView的实现类本身有较多依赖,可以让容器负责实例化,通过初始化方法传递category这类运行时参数:

public class CategoryViewFactory : ICategoryViewFactory
{
    private readonly IServiceProvider _serviceProvider;

    public CategoryViewFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public ICategoryView? Create(CategoryType type, Category category)
    {
        return type switch
        {
            CategoryType.Category => _serviceProvider.GetRequiredService<CategoryView>().Initialize(category),
            CategoryType.Subcategory => _serviceProvider.GetRequiredService<SubcategoryView>().Initialize(category),
            _ => null
        };
    }
}

// 修改视图类,添加初始化方法
public class CategoryView : ICategoryView
{
    public CategoryView() { } // 无参构造允许容器解析

    public ICategoryView Initialize(Category category)
    {
        // 处理category初始化逻辑
        return this;
    }
}

public class SubcategoryView : ICategoryView
{
    private readonly ActiveProgressions _activeProgressions;

    public SubcategoryView(ActiveProgressions activeProgressions)
    {
        _activeProgressions = activeProgressions;
    }

    public ICategoryView Initialize(Category category)
    {
        // 处理category初始化逻辑
        return this;
    }
}

总结

  • 单例场景下当前实现完全合规,符合DI设计原则;
  • 瞬态场景下,优先选择拆分独立创建者的方案,它的扩展性和可维护性最优;服务定位器适合快速解决简单问题;视图由容器管理的方案适合视图本身依赖复杂的场景。

内容的提问来源于stack exchange,提问作者Dasic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 05:45:31